我想要创建一个线程并使用一个事件对象来控制它。确切地说,我希望在设置事件对象时执行线程,并反复等待它。
下面是我所想到的一个粗略的逻辑。
import threading
import time
e = threading.Event()
def start_operation():
e.wait()
while e.is_set():
print('STARTING TASK')
e.clear()
t1 = threading.Thread(target=start_operation)
t1.start()
e.set() # first set
e.set() # second set
我期望t1
在the first set
被命令后运行,并停止运行(因为它内部有e.clear
),然后在the second set
被命令之后再次运行。所以,按照我的预期,它应该打印两次“开始任务”。但它只展示了一次,我不明白为什么。在设置事件对象时,我应该如何更改代码,使其再次运行while loop
?
发布于 2018-06-18 16:57:38
第一个问题是,一旦退出了while
循环,就退出了它。更改谓词返回不会改变任何事情。暂时忘掉这些事件,看看下面的代码:
i = 0
while i == 0:
i = 1
显然,如果您稍后再次设置i = 0
并不重要,对吗?您已经离开了while循环和整个函数。你的代码也在做同样的事情。
只需在整个过程中添加另一个while
循环,就可以解决这个问题:
def start_operation():
while True:
e.wait()
while e.is_set():
print('STARTING TASK')
e.clear()
然而,这仍然是行不通的--也许只是偶尔,偶然的。
Event.set
不阻塞;它只是立即设置事件,即使已经设置了事件。因此,这里最有可能的控制流是:
e.wait()
和块。e.set()
并设置事件。e.set()
并再次设置事件,没有任何效果。e.clear()
。e.wait()
上永远等待。(事实上,没有办法避免事件漏掉的信号,这实际上是创造条件的原因,而且任何比Win32和…更新的东西都不关心事件…。但这里的条件也是不够的。)
如果希望主线程阻塞直到事件清除,然后再设置它,则不能这样做。您需要一些额外的东西,比如第二个事件,主线程可以等待,后台线程可以设置。
但是,如果要跟踪多个set
调用,而不缺少任何调用,则需要使用不同的同步机制。queue.Queue
在这里可能有些过分,但是在Python中做起来非常简单,所以让我们使用它吧。当然,您实际上没有任何值可以放在队列中,但这没关系;您只需将一个虚拟值放在那里:
import queue
import threading
q = queue.Queue()
def start_operation():
while True:
_ = q.get()
print('STARTING TASK')
t1 = threading.Thread(target=start_operation)
t1.start()
q.put(None)
q.put(None)
如果以后想要添加关闭后台线程的方法,只需将其更改为将值粘贴到:
import queue
import threading
q = queue.Queue()
def start_operation():
while True:
if q.get():
return
print('STARTING TASK')
t1 = threading.Thread(target=start_operation)
t1.start()
q.put(False)
q.put(False)
q.put(True)
https://stackoverflow.com/questions/50919167
复制相似问题