Python SIGINT not catched
Question: I don't manage to understand why my SIGINT is never catched by the piece of
code below.

    
    
    #!/usr/bin/env python
    from threading import Thread
    from time import sleep
    import signal
    
    class MyThread(Thread):
        def __init__(self):
            Thread.__init__(self)
            self.running = True
    
        def stop(self):
            self.running = False
    
        def run(self):
            while self.running:
                for i in range(500):
                    col = i**i
                    print col
                    sleep(0.01)
    
    global threads
    threads = []
    
    for w in range(150):
        threads.append(MyThread())
    
    def stop(s, f):
        for t in threads:
            t.stop()
    
    signal.signal(signal.SIGINT, stop)
    
    for t in threads:
        t.start()
    
    for t in threads:
        t.join()
    

To clean this code I would prefer try/except the join() and closing all
threads in case of exception, would that work?


Answer: One of the problems with multithreading in python is that `join()` more or
less disables signals.

This is because the signal can only be delivered to the main thread, but the
main thread is already busy with performing the `join()` and the join is not
interruptible.

You can deduce this from the documentation of the `signal` module

> Some care must be taken if both signals and threads are used in the same
> program. The fundamental thing to remember in using signals and threads
> simultaneously is: always perform signal() operations in the main thread of
> execution. Any thread can perform an alarm(), getsignal(), pause(),
> setitimer() or getitimer(); only the main thread can set a new signal
> handler, and **the main thread will be the only one to receive signals**
> (this is enforced by the Python signal module, even if the underlying thread
> implementation supports sending signals to individual threads). This means
> that signals can’t be used as a means of inter-thread communication. Use
> locks instead.

You can work your way around it, by busy-looping over the join operation:

    
    
    for t in threads:
        while t.isAlive():
            t.join(timeout=1)
    

This is, however, none to efficient:

> The workaround of calling join() with a timeout has a drawback: Python's
> threading wait routine polls 20 times a second when given any timeout. All
> this polling can mean lots of CPU interrupts/wakeups on an otherwise idle
> laptop and drain the battery faster.

Some more details are provided here:

[Python program with thread can't catch
CTRL+C](http://stackoverflow.com/questions/19652446/python-program-with-
thread-cant-catch-ctrlc)

Bug reports for this problem with a discussion of the underlying issue can be
found here:

<https://bugs.python.org/issue1167930>

<https://bugs.python.org/issue1171023>

