How to terminate a thread when main program ends?
Asked Answered
S

6

102

If I have a thread in an infinite loop, is there a way to terminate it when the main program ends (for example, when I press Ctrl+C)?

Sirkin answered 1/4, 2010 at 22:44 Comment(0)
R
48

Check this question. The correct answer has great explanation on how to terminate threads the right way: Is there any way to kill a Thread in Python?

To make the thread stop on Keyboard Interrupt signal (ctrl+c) you can catch the exception "KeyboardInterrupt" and cleanup before exiting. Like this:

try:
    start_thread()  
except (KeyboardInterrupt, SystemExit):
    cleanup_stop_thread()
    sys.exit()

This way you can control what to do whenever the program is abruptly terminated.

You can also use the built-in signal module that lets you setup signal handlers (in your specific case the SIGINT signal): http://docs.python.org/library/signal.html

Relinquish answered 1/4, 2010 at 22:51 Comment(3)
Thanks a lot for your reply. I might have not stated the question correctly. In the example given in that question it was still necessary to execute the thread's stop() function. When I terminate a program abnormally by ctrl+C, that can't happen. So, my question is a bit like, "how do I call the mythread.stop() funcion if the main thread flow is interrupted"Sirkin
Is cleanup_stop_thread() a global function that I can use? or should I need to implement it?Igneous
@alper, I think maybe it was just an example that is possible to implement something. You should implement thatCalyx
G
133

If you make your worker threads daemon threads, they will die when all your non-daemon threads (e.g. the main thread) have exited.

http://docs.python.org/library/threading.html#threading.Thread.daemon

Gumbo answered 1/4, 2010 at 23:35 Comment(5)
Thanks for the simple and precise answer, the default threading.Thread daemon status isDaemon() is False, set it True by setDaemon(True).Headed
This answers the question and just works. The op did not ask how to exit threads cleanly in general.Coagulum
isDaemon() and setDaemon() are old getters/setters (as per the linked doc above), just use daemon=True in threading.Thread()Baroda
Note that using daemon threads can cause other issues and is probably not what you want here: #20597418Synoptic
To avoid using daemon threads and cleanly kill threads, see #58910872Brahmanism
R
48

Check this question. The correct answer has great explanation on how to terminate threads the right way: Is there any way to kill a Thread in Python?

To make the thread stop on Keyboard Interrupt signal (ctrl+c) you can catch the exception "KeyboardInterrupt" and cleanup before exiting. Like this:

try:
    start_thread()  
except (KeyboardInterrupt, SystemExit):
    cleanup_stop_thread()
    sys.exit()

This way you can control what to do whenever the program is abruptly terminated.

You can also use the built-in signal module that lets you setup signal handlers (in your specific case the SIGINT signal): http://docs.python.org/library/signal.html

Relinquish answered 1/4, 2010 at 22:51 Comment(3)
Thanks a lot for your reply. I might have not stated the question correctly. In the example given in that question it was still necessary to execute the thread's stop() function. When I terminate a program abnormally by ctrl+C, that can't happen. So, my question is a bit like, "how do I call the mythread.stop() funcion if the main thread flow is interrupted"Sirkin
Is cleanup_stop_thread() a global function that I can use? or should I need to implement it?Igneous
@alper, I think maybe it was just an example that is possible to implement something. You should implement thatCalyx
L
34

Try to enable the sub-thread as daemon-thread.

Recommended:

from threading import Thread

t = Thread(target=desired_method)
t.daemon = True  # Dies when main thread (only non-daemon thread) exits.
t.start()

Inline:

t = Thread(target=desired_method, daemon=True).start()

Old API:

t.setDaemon(True)
t.start()

When your main thread terminates (e.g. Ctrl+C keystrokes), other threads will also be killed by the instructions above.

Lineman answered 7/8, 2018 at 9:28 Comment(1)
Note that using daemon threads can cause other issues and are probably not what you want here: #20597418Synoptic
T
12

Use the atexit module of Python's standard library to register "termination" functions that get called (on the main thread) on any reasonably "clean" termination of the main thread, including an uncaught exception such as KeyboardInterrupt. Such termination functions may (though inevitably in the main thread!) call any stop function you require; together with the possibility of setting a thread as daemon, that gives you the tools to properly design the system functionality you need.

Threshold answered 2/4, 2010 at 2:43 Comment(3)
Note that this approach worked without requiring daemonized threads in Python versions prior to 2.6.5, see answer to #3713860. This is unfortunate IMHO, since daemon threads during shutdown are a bit of a mess before python 3.4 (bugs.python.org/issue19466). If you stop and join your daemon threads in your atexit handlers, all should be fine, at the (probably insignificant) cost of serializing your thread teardown.Camisole
Be aware that weird things can happen because of post-poned atexit.register() calls in Python modules, causing your termination procedure to be executed after the multiprocessing's one. I run in this problem dealing with Queue and daemon threads: “EOF error” at program exit using multiprocessing Queue and Thread.Transom
Apparently in modern versions of Python, such as 3.7.4+, the atexit handlers aren't called when non-daemon threads are alive and the main thread exits. See Script stuck on exit when using atexit to terminate threads.Sympathy
L
9

If you spawn a Thread like so - myThread = Thread(target = function) - and then do myThread.start(); myThread.join(). When CTRL-C is initiated, the main thread doesn't exit because it is waiting on that blocking myThread.join() call. To fix this, simply put in a timeout on the .join() call. The timeout can be as long as you wish. If you want it to wait indefinitely, just put in a really long timeout, like 99999. It's also good practice to do myThread.daemon = True so all the threads exit when the main thread(non-daemon) exits.

Lapoint answered 13/8, 2013 at 21:25 Comment(2)
myThread.daemon = True is a wonderful solution to this problem.Budge
@Budge .daemon=True is in not a solid solution. Check this thread for an explanation: https://mcmap.net/q/212096/-python-exception-in-thread-thread-1-most-likely-raised-during-interpreter-shutdownFillender
Q
6

Daemon threads are killed ungracefully so any finalizer instructions are not executed. A possible solution is to check is main thread is alive instead of infinite loop.

E.g. for Python 3:

while threading.main_thread().isAlive():
    do.you.subthread.thing()
gracefully.close.the.thread()

See Check if the Main Thread is still alive from another thread.

Quarterphase answered 21/8, 2019 at 6:8 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.