threading模块:Lock与RLock的区别
请解释threading.Lock和threading.RLock(可重入锁)的区别。什么是死锁?如何在同一个线程中安全地多次获取同一把锁?RLock的底层实现原理(acquire计数+所有者线程)是什么?给出一个避免死锁的实际编码示例。
回答
孤独的心
Lock(互斥锁):最基本的锁,同一线程连续两次acquire()会导致死锁。
RLock(可重入锁):允许同一线程多次acquire(),通过维护所有者线程和递归计数实现。
lock = threading.Lock()
lock.acquire()
lock.acquire() # 死锁!
rlock = threading.RLock()
rlock.acquire()
rlock.acquire() # OK,计数为2
rlock.release() # 计数1
rlock.release() # 计数0,真正释放
死锁示例:
lock1, lock2 = Lock(), Lock()
def thread_a():
lock1.acquire()
lock2.acquire() # 可能死锁
def thread_b():
lock2.acquire()
lock1.acquire() # 与A形成循环等待
避免死锁的最佳实践:
- 固定锁获取顺序(锁排序锁)
- 使用
with语句自动释放 acquire(timeout=...)超时机制- 使用
contextlib或线程安全数据结构替代手动锁
# 安全写法
with lock:
# 临界区
pass