threading.Condition.wait(timeout) 忽略 threading.Condition.notify()

3 投票
1 回答
2519 浏览
提问于 2025-04-18 09:15

我有一个应用程序,它使用了两个线程。我想通过等待一个条件变量 exitCondition 来关闭这两个线程。我使用的是 Python 3.3,这个版本和 Python 2.7 不一样,threading.Condition.wait() 在条件被通知时会返回 True,而在超时的情况下则返回 False

#!/usr/bin/python
import threading
from time import sleep

exitCondition = threading.Condition()

def inputActivity():
    while True:
        exitCondition.acquire()
        exitConditionReached = exitCondition.wait(.1) #<-critical
        print(exitConditionReached)
        exitCondition.release()
        if exitConditionReached: #exitCondition reached -> shutdown
            return
        else: #exitCondition not reached -> do work
            sleep(.1)

inThread = threading.Thread(target = inputActivity)
inThread.start()

sleep(.2) #<-critical

exitCondition.acquire()
exitCondition.notify()
print("exitCondition notified")
exitCondition.release()

inThread.join()

在第10行和第21行有两行带有 #<-critical 注释的代码。如果 sleep 的时间不一致(比如 .25 和 .1),程序会终止。如果 sleep 的时间一致(比如 .2 和 .1),那么 inThread 会无限运行,永远打印 false。我觉得这像是一个竞争条件,显然如果 notifywait 同时被调用,通知就不会被识别。我原以为 exitCondition.acquire()exitCondition.release() 是用来防止这种情况的。我的问题是,为什么这个条件变量不是线程安全的,我该怎么解决。理想情况下,我希望能写 wait(0),并确保不会错过任何通知。

1 个回答

3

如果在工作线程正在执行任务的时候(比如说在调用 sleep(.1) 的时候,或者在其他任何地方,而不是在 .wait 调用的时候),你调用了 exitCondition.notify,那么你描述的行为正是我所预期的。只有在 wait 期间发生通知时,wait 调用才会返回 True

在我看来,这种情况更适合使用 threading.Event 而不是 threading.Condition:把 threading.Condition 替换成 threading.Event,把 notify 调用替换成 set 调用,并且在两个线程中都去掉 acquirerelease 的调用。

也就是说,代码应该像这样:

#!/usr/bin/python
import threading
from time import sleep

exitCondition = threading.Event()

def inputActivity():
    while True:
        exitConditionReached = exitCondition.wait(.1) #<-critical
        print(exitConditionReached)
        if exitConditionReached: #exitCondition reached -> shutdown
            return
        else: #exitCondition not reached -> do work
            sleep(.1)

inThread = threading.Thread(target = inputActivity)
inThread.start()

sleep(.2) #<-critical

exitCondition.set()
print("exitCondition set")

inThread.join()

当你做到这一点后,你就不需要第一个 .wait 了:你可以用直接的 is_set 调用来检查退出条件是否已经设置:

#!/usr/bin/python
import threading
from time import sleep

exitCondition = threading.Event()

def inputActivity():
    while True:
        if exitCondition.is_set(): #exitCondition reached -> shutdown
            return
        else: #exitCondition not reached -> do work
            sleep(.1)

inThread = threading.Thread(target = inputActivity)
inThread.start()

sleep(.2) #<-critical

exitCondition.set()
print("exitCondition set")

inThread.join()

撰写回答