调用Event.set()后未通知threading.Event().wait()

2024-04-18 11:56:19 发布

您现在位置:Python中文网/ 问答频道 /正文

我在使用threading.Event()时遇到一个非常奇怪的问题,无法理解发生了什么?我一定漏掉了什么,你能指出吗?

我有一个侦听器类,它与信号处理程序共享同一事件对象,下面是我的简化代码:

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

每一秒。但它会打印出来:

Listener is terminated ...

按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,一旦标志为true,调用wait()的event.wait()线程就不会阻塞。顺便说一下,我正在使用Python2.7.3。


Tags: selfeventforsignalisdefhandlermessages
3条回答

有几个线程讨论与python的线程、中断、锁、事件相关的问题。

例如,请参见herehere,但还有更多。

python3的情况要好得多,它改进了wait()的实现,使其不可中断。

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

差异:

  1. Thread类划分为子类,使用run(vs start)

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

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

  4. 主进程在从pause()唤醒后触发Event.set()——主进程将对任何信号执行此操作,而不仅仅是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

这对你有用吗?基本上,为监听器启动另一个线程并在那里等待主线程等待信号。

#!/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 

相关问题 更多 >