threading.Condition.wait(timeout) 忽略 threading.Condition.notify()
我有一个应用程序,它使用了两个线程。我想通过等待一个条件变量 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
。我觉得这像是一个竞争条件,显然如果 notify
和 wait
同时被调用,通知就不会被识别。我原以为 exitCondition.acquire()
和 exitCondition.release()
是用来防止这种情况的。我的问题是,为什么这个条件变量不是线程安全的,我该怎么解决。理想情况下,我希望能写 wait(0)
,并确保不会错过任何通知。
1 个回答
如果在工作线程正在执行任务的时候(比如说在调用 sleep(.1)
的时候,或者在其他任何地方,而不是在 .wait
调用的时候),你调用了 exitCondition.notify
,那么你描述的行为正是我所预期的。只有在 wait
期间发生通知时,wait
调用才会返回 True
。
在我看来,这种情况更适合使用 threading.Event
而不是 threading.Condition
:把 threading.Condition
替换成 threading.Event
,把 notify
调用替换成 set
调用,并且在两个线程中都去掉 acquire
和 release
的调用。
也就是说,代码应该像这样:
#!/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()