在 Python 中,Condition
对象用于线程同步,其 wait()
方法用于释放锁并阻塞线程,直到被其他线程唤醒。使用不当可能导致死锁、虚假唤醒或逻辑错误。以下是常见问题及修复方案:
常见问题与修复方案
1. 未检查条件(虚假唤醒)
问题:
wait()
可能被虚假唤醒(即使未收到notify()
),若用if
检查条件,唤醒后可能条件仍未满足。python
with cond: if not resource_ready: # ❌ 错误:应用 while 而非 if cond.wait()
修复:始终用
while
循环检查条件:python
with cond: while not resource_ready: # ✅ 正确:循环检查条件 cond.wait()
2. 未在持有锁时调用 wait()
问题:调用
wait()
前未获取关联锁,抛出RuntimeError
。python
cond = threading.Condition() cond.wait() # ❌ 错误:未先获取锁
修复:确保在
with
块或acquire()
/release()
中调用:python
with cond: # ✅ 正确:自动获取/释放锁 while not ready: cond.wait()
3. 未正确配对 notify()
和 wait()
问题:
notify()
未在修改条件的代码块中调用,导致信号丢失。python
def producer(): resource_ready = True # ❌ 错误:未在锁内修改条件 cond.notify() # 可能错过唤醒
修复:修改条件和调用
notify()
必须在同一锁内:python
def producer(): with cond: resource_ready = True # ✅ 在锁内修改条件 cond.notify() # 安全唤醒
4. 未使用超时导致永久阻塞
问题:若生产者线程失败,消费者可能永久阻塞。
修复:为
wait()
添加timeout
参数并处理超时:python
with cond: while not resource_ready: if not cond.wait(timeout=5.0): # 等待5秒 print("Timeout, exiting") break
5. 错误使用 notify()
而非 notify_all()
问题:
notify()
只唤醒一个线程,若多个线程等待相同条件,可能遗漏唤醒。修复:需要唤醒所有线程时使用
notify_all()
:python
with cond: resource_ready = True cond.notify_all() # ✅ 唤醒所有等待线程
完整正确示例
python
import threading # 共享资源与条件变量 resource_ready = False cond = threading.Condition() def consumer(): with cond: while not resource_ready: # 循环检查条件 cond.wait() # 释放锁并等待 print("Resource is ready!") def producer(): with cond: global resource_ready resource_ready = True # 修改条件 cond.notify_all() # 唤醒所有等待线程 # 启动线程 threading.Thread(target=consumer).start() threading.Thread(target=producer).start()
关键实践总结
检查条件:始终用
while
循环检查条件(防虚假唤醒)。锁的作用域:
wait()
、notify()
及条件修改必须在同一锁内。唤醒选择:
notify()
:唤醒 1 个线程(效率高)。notify_all()
:唤醒 所有线程(避免遗漏)。
超时机制:用
wait(timeout=seconds)
防止永久阻塞。资源状态:条件变量应关联明确的共享状态(如
resource_ready
)。
遵循这些模式可避免 Condition
的常见陷阱,确保线程安全。