我在使用threading.Event()时遇到了一个非常奇怪的问题,无法理解发生了什么?我一定是漏掉了什么,你能指出来吗?
我有一个Listener类,它与信号处理程序共享相同的事件对象,下面是我的简化代码:
import threading, time
class Listener(object):
def __init__(self, event):
super(Listener, self).__init__()
self.event = event
def start(self):
while not self.event.is_set():
print("Listener started, waiting for messages ...")
self.event.wait()
print("Listener is terminated ...")
self.event.clear()
event = threading.Event()
def handler(signum, frame):
global event
event.set()
print('Signal handler called with signal [%s]' % signum)
if __name__ == "__main__":
signal.signal(signal.SIGINT, handler)
listener = Listener(event)
listener.start()
在我运行代码之后,我按ctrl+c来中断它,实际上什么也没有发生。如果我想退出,我必须使用kill -9来终止进程。但是如果我给event.wait()
提供一个参数,它就起作用了。但是它一直输出:
Listener started, waiting for messages…"
每超时1秒。但是它会打印出:
监听器终止…
按Ctrl+c,这是我想要的
while not self.event.is_set():
print("Listener started, waiting for messages ...")
self.event.wait(1)
为什么我必须在event.wait()
中给出超时参数以使其响应ctrl+c事件?根据http://docs.python.org/2/library/threading.html#event-objects文档,event.wait()线程调用wait()
一旦标志为真将不会阻塞。顺便说一下,我使用的是python 2.7.3
有几个线程讨论与python的线程,中断,锁,事件相关的问题。
例如,见这里和这里,但还有更多。
在python3中情况要好得多,wait()
的实现得到了改进,使其可中断。
这对你有用吗?基本上,为Listener启动另一个线程,并在主线程等待信号时在那里等待。
#!/usr/bin/python
import threading, signal
class Listener(threading.Thread):
def __init__(self, event):
super(Listener, self).__init__()
self.event = event
def run(self):
while not self.event.is_set():
print("Listener started, waiting for messages ...")
self.event.wait()
print("Listener is terminated ...")
self.event.clear()
event = threading.Event()
def handler(signum, frame):
global event
event.set()
print('Signal handler called with signal [%s]' % signum)
if __name__ == "__main__":
signal.signal(signal.SIGINT, handler)
listener = Listener(event)
listener.start()
while listener.is_alive():
pass
以下代码与原始代码相似。
差异:
-
Thread
类的子类,使用run
(vs start) -
使用没有超时的简单
wait()
,这是更可预测的 -
信号处理程序不直接触发
Event
。相反,它只是隐式唤醒位于signal.pause()
上的主进程。 -
main进程在从
pause()
唤醒后触发Event.set()
——main进程将在任何信号上执行此操作,而不仅仅是SIGINT
(control-C)。出于测试目的,两秒钟后会发出警报。
希望这对你有帮助!
import signal, threading, time
class Listener(threading.Thread):
def __init__(self, event):
super(Listener, self).__init__()
self.event = event
def run(self):
print("Listener started, waiting for messages ...")
while not self.event.wait():
print('(timeout)')
print("Listener is terminated ...")
self.event.clear()
event = threading.Event()
def handler(signum, _frame):
# global event
# event.set()
print('Signal handler called with signal [%s]' % signum)
if __name__ == "__main__":
signal.signal(signal.SIGINT, handler)
signal.signal(signal.SIGALRM, handler)
signal.alarm(2)
listener = Listener(event)
listener.start()
print '* PAUSE'
signal.pause() # wait for a signal
print '* SIGNALLING'
event.set()
listener.join()
print('* DONE')
输出Listener started, waiting for messages ...
* PAUSE
Signal handler called with signal [14]
* SIGNALLING
Listener is terminated ...
* DONE
import signal, threading, time
class Listener(threading.Thread):
def __init__(self, event):
super(Listener, self).__init__()
self.event = event
def run(self):
print("Listener started, waiting for messages ...")
while not self.event.wait():
print('(timeout)')
print("Listener is terminated ...")
self.event.clear()
event = threading.Event()
def handler(signum, _frame):
# global event
# event.set()
print('Signal handler called with signal [%s]' % signum)
if __name__ == "__main__":
signal.signal(signal.SIGINT, handler)
signal.signal(signal.SIGALRM, handler)
signal.alarm(2)
listener = Listener(event)
listener.start()
print '* PAUSE'
signal.pause() # wait for a signal
print '* SIGNALLING'
event.set()
listener.join()
print('* DONE')
Listener started, waiting for messages ...
* PAUSE
Signal handler called with signal [14]
* SIGNALLING
Listener is terminated ...
* DONE