Python Condition对象wait方法使用与修复

发布于:2025-08-17 ⋅ 阅读:(16) ⋅ 点赞:(0)

在 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()

关键实践总结

  1. 检查条件:始终用 while 循环检查条件(防虚假唤醒)。

  2. 锁的作用域wait()notify() 及条件修改必须在同一锁内

  3. 唤醒选择

    • notify():唤醒 1 个线程(效率高)。

    • notify_all():唤醒 所有线程(避免遗漏)。

  4. 超时机制:用 wait(timeout=seconds) 防止永久阻塞。

  5. 资源状态:条件变量应关联明确的共享状态(如 resource_ready)。

遵循这些模式可避免 Condition 的常见陷阱,确保线程安全。


网站公告

今日签到

点亮在社区的每一天
去签到