症状
进程挂起,若干线程处于阻塞状态且不再有任何输出。CPU 空闲,因为所有线程都在等待,这正是死锁而非忙循环的特征。
诊断
挂起时导出线程栈:
import faulthandler
faulthandler.dump_traceback_later(10, repeat=False)
栈信息会显示某个线程持有 A 锁等待 B 锁,而另一个持有 B 锁等待 A 锁。
修复
统一加锁顺序并保证释放:
import threading
_lo = threading.Lock() # always acquire in this order
_hi = threading.Lock()
def transfer():
with _lo, _hi: # consistent order, released on exception
do_work()
lock = threading.Lock()
if not lock.acquire(timeout=5):
raise TimeoutError('lock contention')
仅在确实需要可重入时使用 RLock。
验证
运行原会死锁的负载;它顺利完成且无阻塞线程,且断言 acquire(timeout=…) 成功的测试证明统一顺序消除了环路。