Ctrl-C i.e. KeyboardInterrupt to kill threads in Python

If you want to have main thread to receive the CTRL+C signal while joining, it can be done by adding timeout to join() call.

The following seems to be working (don't forget to add daemon=True if you want main to actually end):

thread1.start()
while True:
    thread1.join(600)
    if not thread1.isAlive():
        break

The problem there is that you are using thread1.join(), which will cause your program to wait until that thread finishes to continue.

The signals will always be caught by the main process, because it's the one that receives the signals, it's the process that has threads.

Doing it as you show, you are basically running a 'normal' application, without thread features, as you start 1 thread and wait until it finishes to continue.


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, daemon=True)  # create a daemon child thread
        thread.start()

        while thread.is_alive():
            thread.join(1)  # join shortly to not block KeyboardInterrupt exceptions
    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 exceptions
    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