I want to stop my program when the user presses ctrl-C.
The following answer suggests catching the KeyboardInterrupt
exception.
python: how to terminate a thread when main program ends
Sometimes it works. But in the following example, it stops working after I increase the number of threads from 25 to 30.
import threading, sys, signal, os
stderr_lock = threading.Lock()
def Log(module, msg):
with stderr_lock:
sys.stderr.write("%s: %s\n" % (module, msg))
class My_Thread(threading.Thread):
def __init__(self):
threading.Thread.__init__(self)
Log("Init", "Initing.")
self.start()
def run(self):
try:
while True:
Log("Run", "Running.")
except KeyboardInterrupt:
os._exit(0)
for i in range(30):
My_Thread()
# trap ctrl-C in main thread
try:
while True:
pass
except KeyboardInterrupt:
os._exit(0)
This has a very suspiciously similar feel to the following question:
Thread-Safe Signal API in Python 2.7
In that case, I was unable to catch signals after increasing the number of threads beyond 87.
There are actually two different issues with your code that gives this behavior. The first is that your threads should be made into
daemon
threads, so that they automatically stops when the main thread exits, the second is that yourtry
block does not encapsulate the thread creation and start-up.When you create a number of threads, the thread creation won't be finished for quite a while (since it is continuously interrupted by the created threads and the GIL prevents them to run in parallel). Therefore, you send your
KeyboardInterrupt
before being set up to be handled. However, theKeyboardInterrupt
will still kill the main thread (with a Traceback), but not the child threads.Thus, your code works if you modify it as:
Note, that making the threads into daemons is not strictly necessary in the current example, but I would consider that to be good practice for threads that are supposed to end when the main program ends.