以下程序挂起终端,忽略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()
答案 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')
旧的民意调答:
您可以尝试允许解释器运行主线程:
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。