← 中文资源

简体中文版本

Python: 使用锁导致的线程死锁

诊断 Python 线程死锁:锁顺序、不可重入锁与忘记释放,并通过超时与统一加锁顺序修复。

阅读英文原文

症状

进程挂起,若干线程处于阻塞状态且不再有任何输出。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=…) 成功的测试证明统一顺序消除了环路。