编程面试要素中的死锁题19.5

con*_*ein 5 python multithreading locking

这个来自编程面试元素的问题声称,在“U1 启动到 U2 的传输,然后 U2 立即启动到 U1 的传输的场景中,以下代码中存在死锁。由于每次传输都发生在单独的线程中,因此可能第一个线程锁定 U1,然后第二个锁定 U2”

class Account:
    _global_id = 0

    def __init__(self, balance):
        self._balance = balance
        self._id = Account._global_id
        Account._global_id += 1
        self._lock = threading.RLock()

    def get_balance(self):
        return self._balance

    @staticmethod
    def transfer(acc_from, acc_to, amount):
        th = threading.Thread(target=acc_from._move, args=(acc_to, amount))
        th.start()

    def _move(self, acc_to, amount):
        with self._lock:
            if amount > self._balance:
                return False
            acc_to._balance += amount
            self._balance -= amount
            print('returning True')
            return True
Run Code Online (Sandbox Code Playgroud)

我看不出在那种情况下会出现僵局。U1 和 U2 有单独的锁,据我所知,线程 1 只锁定 U1,线程 2 锁定 U2,因为 _move 方法只使用 self._lock 并且不接触 acc_to._lock。我错过了什么?

aks*_*pal 0

我也有同样的疑问,在书的网站上没有发现已知的错误。根据这个问题之前的部分对死锁的解释,我认为应该是

def _move(self, acc_to, amount):
        with self._lock, acc_to._lock:
Run Code Online (Sandbox Code Playgroud)

代替

def _move(self, acc_to, amount):
        with self._lock:
Run Code Online (Sandbox Code Playgroud)

因为这是发生死锁的主要方式。