In Python, it is true that KeyboardInterrupt
exceptions are raised only in the main thread of each process. But as other answers mentionned, it is also true that the method Thread.join
blocks the calling thread, including KeyboardInterrupt
exceptions. That is why Ctrl+C seems to have no effect: the execution in the main thread remains blocked at the line thread.join()
.
So a simple solution to your question is to firstly, add a timeout argument to thread.join()
and put that call in a loop that ends when the child thread exits, so that KeyboardInterrupt
exceptions can be raised after each timeout, and secondly, make the child thread daemonic, which means that its parent (the main thread here) will kill it when it exits (only non-daemon threads are not killed but joined when their parent exits):
def main():
try:
thread = threading.Thread(target=f)
thread.daemon = True # create a daemon child thread
thread.start()
while thread.is_alive():
thread.join(1) # join shortly to not block KeyboardInterrupt
except KeyboardInterrupt:
print "Ctrl+C pressed..."
sys.exit(1)
def f():
while True:
pass # do the actual work
But a better solution, if you control the child thread's code, is to inform the child thread to exit gracefully (instead of abruptly like with the first solution), for instance with a threading.Event
:
def main():
try:
event = threading.Event()
thread = threading.Thread(target=f, args=(event,))
thread.start()
event.wait() # wait forever but without blocking KeyboardInterrupt
except KeyboardInterrupt:
print "Ctrl+C pressed..."
event.set() # inform the child thread that it should exit
sys.exit(1)
def f(event):
while not event.is_set():
pass # do the actual work