Interrupting the keyboard in a program waiting for an event
The following program hangs on the terminal in such a way that it ignores Ctrl+C
. This is quite annoying as I have to restart the terminal every time one of the threads hangs.
Is there a way to catch KeyboardInterrupt
while waiting for an event?
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()
source to share
Update: As of current Python 3 is finished_event.wait()
running on my Ubuntu machine (since Python 3.2). You don't need to supply a parameter timeout
in order to interrupt it with Ctrl+C. You need to pass a parameter timeout
to CPython 2.
Here's a complete sample code:
#!/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')
Maybe bugs , associated with the Ctrl + the C . Check if it works in your environment.
Old poll answer:
You can try to allow the interpreter to start the main thread:
while not finished_event.wait(.1): # timeout in seconds
pass
If you just want to wait for the child thread to execute:
while thread.is_alive():
thread.join(.1)
source to share
If you want to avoid polling, you can use pause()
the signal module function instead finished_event.wait()
. signal.pause()
is a blocking function and is unblocked when a signal is received by a process. In this case, when the ^ C key is pressed, the SIGINT signal will unlock the function. Please note that this feature does not work on Windows according to the documentation. I tried this on Linux and it worked for me.
I found this solution on this SO thread .
source to share
You can also fix the Event.wait () function like this:
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
This works because wait () with a timeout argument calls KeyboardInterrupt.
source to share