7

以下程序挂起终端,使其忽略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

4 回答 4

5

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

我在这个 SO线程中遇到了这个解决方案。

于 2015-06-14T16:24:23.607 回答
4

更新:在当前的 Python 3finished_event.wait()上,我的 Ubuntu 机器上工作(从 Python 3.2 开始)。您无需指定timeout参数,即可使用Ctrl+C. 您需要timeout在 CPython 2 上传递参数。

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

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

可能存在与Ctrl+C相关的错误。测试它是否适用于您的环境。


旧投票答案:

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

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

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

while thread.is_alive():
    thread.join(.1)
于 2013-01-20T03:02:31.143 回答
1

您还可以通过以下方式修补 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。

于 2015-10-03T10:38:11.093 回答
1

基于@Pete's answer,但使用子类化和使用实际Event.wait方法,只是使用较小的超时来允许KeyboardInterrupt在两者之间处理 s 等:

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)
于 2020-03-18T12:36:54.267 回答