在正在等待事件的程序中捕获键盘中断

时间:2013-01-20 02:29:31

标签: python windows multithreading windows-7 python-3.x

以下程序挂起终端,忽略Ctrl+C。这很烦人,因为每次有一个线程挂起时我都要重启终端。

在等待活动时有没有办法抓住KeyboardInterrupt

import threading
def main():
    finished_event = threading.Event()
    startThread(finished_event)
    finished_event.wait()#I want to stop the program here
    print('done!')
def startThread(evt):
    """Start a thread that will trigger evt when it is done"""
    #evt.set()
if __name__ == '__main__':
    main()

4 个答案:

答案 0 :(得分:3)

如果您想避免轮询,可以使用signal模块的pause()功能代替finished_event.wait()signal.pause()是一个阻塞函数,当进程收到信号时会被解锁。在这种情况下,当按下^ C时,SIGINT信号解锁该功能。请注意,根据文档,该功能在Windows上不起作用。我在Linux上试过它,它对我有用。

我在此SO thread中遇到了此解决方案。

答案 1 :(得分:1)

更新:在当前的Python 3上finished_event.wait()适用于我的Ubuntu机器(从Python 3.2开始)。您不需要指定timeout参数,使用 Ctrl + C 中断它。您需要在CPython 2上传递timeout参数。

这是一个完整的代码示例:

#!/usr/bin/env python3
import threading

def f(event):
    while True:
        pass
    # never reached, otherwise event.set() would be here

event = threading.Event()
threading.Thread(target=f, args=[event], daemon=True).start()
try:
    print('Press Ctrl+C to exit')
    event.wait()
except KeyboardInterrupt:
    print('got Ctrl+C')

可能bugsCtrl+C有关。测试它是否适用于您的环境。


旧的民意调答:

您可以尝试允许解释器运行主线程:

while not finished_event.wait(.1): # timeout in seconds
    pass

如果您只想等到子线程完成:

while thread.is_alive():
    thread.join(.1)

答案 2 :(得分:1)

基于@Pete的答案,但具有子类化并使用实际的Event.wait方法,只是具有较小的超时时间,以允许处理KeyboardInterrupt,并且介于以下之间:

class InterruptableEvent(threading.Event):
    def wait(self, timeout=None):
        wait = super().wait  # get once, use often
        if timeout is None:            
            while not wait(0.01):  pass
        else:
            wait(timeout)

答案 3 :(得分:0)

您还可以通过以下方式修补Event.wait()函数:

def InterruptableEvent():
    e = threading.Event()

    def patched_wait():
        while not e.is_set():
            e._wait(3)

    e._wait = e.wait
    e.wait = patched_wait
    return e


>>> event = InterruptableEvent()
>>> try:
...     event.wait()
... except KeyboardInterrupt:
...     print "Received KeyboardInterrupt"
... 
^CReceived KeyboardInterrupt

这是有效的,因为带有超时参数的wait()将引发一个KeyboardInterrupt。