Interrupting Python Threads
I'm mulling things over as to how best to interrupt threads with Python using a KeyboardInterrupt and what effectively happens to them whenever you do.
1 The Use Case of that Multithreaded OpenStack Shell I Wrote
In that multithreaded OpenStack shell newstar I wrote, I have a number of threads getting server names from a Queue and running nova show in a subprocess to display information about them. The main thread waits for the Queue to be consumed with Queue.join(). The problem is that Queue.join() cannot be interrupted by a KeyboardInterrupt. Even a SIGINT with a custom handler won't run.
2 Interrupting Sleep Instead
A common suggestion is to have an infinite loop repeatedly wait with time.sleep() and to check if the Queue is empty, as time.sleep() is interruptible. Simply add a Queue.join() call after the loop to make sure it's drained:
try:
while not queue.empty():
time.sleep(10) # Interruptible
except KeyboardInterrupt:
while not queue.empty():
queue.get()
queue.task_done()
queue.join()Note that Thread.join() isn't normally interruptible, but it is at any time when supplied with a timeout argument. It's likely that it simply uses time.sleep() too behind the scenes.
3 What Happens When KeyboardInterrupts Are Issued?
In the beginning I thought that a KeyboardInterrupt would go to the threads currently being joined by the main thread, and any of its running subprocesses, instead of reaching the main thread. I thought I could have some level of control on this by forking and detaching the process from the terminal.
But in fact, a KeyboardInterrupt really hits all the threads – including the main one. The only reason it didn't seem to have any effect on it was simply because the main thread was stuck in that uninterruptible Queue.join().
