Jérôme Belleman
Home  •  Tools  •  Posts  •  Talks  •  Travels  •  Graphics  •  About Me

Interrupting Python Threads

7 Oct 2013

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().

4 References