Cannot kill Python script with Ctrl-C
Solution 1
Ctrl+C terminates the main thread, but because your threads aren't in daemon mode, they keep running, and that keeps the process alive. We can make them daemons:
f = FirstThread()
f.daemon = True
f.start()
s = SecondThread()
s.daemon = True
s.start()
But then there's another problem - once the main thread has started your threads, there's nothing else for it to do. So it exits, and the threads are destroyed instantly. So let's keep the main thread alive:
import time
while True:
time.sleep(1)
Now it will keep print 'first' and 'second' until you hit Ctrl+C.
Edit: as commenters have pointed out, the daemon threads may not get a chance to clean up things like temporary files. If you need that, then catch the KeyboardInterrupt
on the main thread and have it co-ordinate cleanup and shutdown. But in many cases, letting daemon threads die suddenly is probably good enough.
Solution 2
KeyboardInterrupt and signals are only seen by the process (ie the main thread)... Have a look at Ctrl-c i.e. KeyboardInterrupt to kill threads in python
Solution 3
I think it's best to call join()
on your threads when you expect them to die. I've taken the liberty to make the change your loops to end (you can add whatever cleanup needs are required to there as well). The variable die
is checked on each pass and when it's True
, the program exits.
import threading
import time
class MyThread (threading.Thread):
die = False
def __init__(self, name):
threading.Thread.__init__(self)
self.name = name
def run (self):
while not self.die:
time.sleep(1)
print (self.name)
def join(self):
self.die = True
super().join()
if __name__ == '__main__':
f = MyThread('first')
f.start()
s = MyThread('second')
s.start()
try:
while True:
time.sleep(2)
except KeyboardInterrupt:
f.join()
s.join()
Solution 4
An improved version of @Thomas K's answer:
- Defining an assistant function
is_any_thread_alive()
according to this gist, which can terminates themain()
automatically.
Example codes:
import threading
def job1():
...
def job2():
...
def is_any_thread_alive(threads):
return True in [t.is_alive() for t in threads]
if __name__ == "__main__":
...
t1 = threading.Thread(target=job1,daemon=True)
t2 = threading.Thread(target=job2,daemon=True)
t1.start()
t2.start()
while is_any_thread_alive([t1,t2]):
time.sleep(0)

dotancohen
I currently develop and support the backends of a few LAMP-stack based web applications for BSS (Business Support Services) that my company specializes in. I have experience in software project management, business process development, and I ran a software development business for a short time (actually twice). I have been using PHP since 1998 or '99, and I'm reasonably competent in the associated client-side technologies. I find myself using Python often, mostly for my own personal projects, I'm quite poetic in VIM, and of course Git is a cornerstone of my development. Lately I have been experimenting with machine learning, mostly with scikit-learn.
Updated on October 25, 2021Comments
-
dotancohen about 1 year
I am testing Python threading with the following script:
import threading class FirstThread (threading.Thread): def run (self): while True: print 'first' class SecondThread (threading.Thread): def run (self): while True: print 'second' FirstThread().start() SecondThread().start()
This is running in Python 2.7 on Kubuntu 11.10. Ctrl+C will not kill it. I also tried adding a handler for system signals, but that did not help:
import signal import sys def signal_handler(signal, frame): sys.exit(0) signal.signal(signal.SIGINT, signal_handler)
To kill the process I am killing it by PID after sending the program to the background with Ctrl+Z, which isn't being ignored. Why is Ctrl+C being ignored so persistently? How can I resolve this?
-
Tommaso Barbugli over 9 yearsyou should mention that by doing this threads are not stopped gracefully and some resources not released.
-
Thomas K over 9 yearsWell, Ctrl-C is never a graceful way to stop anything. I'm not sure what resources would be left - shouldn't the OS reclaim anything when the process exits?
-
Feuermurmel over 9 years@ThomasK Temporary files created by
tempfile.TemporaryFile()
may be left on disk, for example. -
deed02392 almost 9 yearsIf you don't daemonise am I right in thinking the main thread is 'waiting' just below the last
start()
? Or is it just generally waiting in some other magical state where you can no longer interact with it and it'll only finish after its child threads have? -
Thomas K almost 9 years@deed02392 : I don't know exactly what happens to the main thread, but as far as I know you can't do anything with it after it exits. The process will finish when all non-daemon threads have finished; parent-child relationships don't come into that.
-
vitiral about 8 yearsWould adding a
__del__
method to your classes help with the cleanup problem? (i.e. all classes can handle anything that needs to close there?) -
maxkoryukov about 6 years
while threading.active_count() > 1: time.sleep(1)
is a little bit better. Original post -
Ryan Haining over 4 yearsLooks like in python3 you can pass
daemon=True
toThread.__init__
-
o11c over 3 years
while True
is silly, you shouldjoin
directly - and that overriden function is kind of questionable. Maybedef join(self, force=False): if force: self.die = True
so thatjoin()
is unchanged byjoin(force=True)
kills them. But even then, better to inform both threads before joining either one.