threading.Event().wait()在调用event.set()后不会得到通知



我在使用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 

以下代码与原始代码相似。

差异:

  1. Thread类的子类,使用run (vs start)

  2. 使用没有超时的简单wait(),这是更可预测的

  3. 信号处理程序不直接触发Event。相反,它只是隐式唤醒位于signal.pause()上的主进程。

  4. 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

最新更新