48

What I'm trying to do here is use a keyboard interrupt to exit all ongoing threads in the program. This is a pared down version of my code where the thread is created:

for i in taskDictionary:
    try:
        sleep(60)
        thread = Thread(target = mainModule.executeThread)
        thread.start()
    except KeyboardInterrupt:
        thread.__stop()

The program itself is far more complicated, accounting for tons of different variables that affect the threads and even having the option to launch in a sequential mode, where tasks are not threaded, but instead launched one-by-one so there might be some problems with this small variation I just conjured up. I have done this in ways that produced 50/50 results. The interrupts would work but the threads would never cleanly exit. Sometimes they would keep going but halt the execution of future threads, some times they would exit with a massive error regarding the interrupt, other times the interrupts would do nothing at all. Last time I ran this the program stopped any future threads from executing but did not stop the current thread. Is there any way to exit the threads without going into the module the thread is actually executing in?

Joe
  • 835
  • 2
  • 9
  • 20

2 Answers2

76

A similar question is "How do you kill a thread?"

You create an exit handler in your thread that is controlled by a lock or event object from the threading module. You then simply remove the lock or signal the event object. This informs the thread it should stop processing and exit gracefully. After signaling the thread in your main program, the only thing left to do is to use the thread.join() method in main which will wait for the thread to shut down.

A short example:

import threading
import time

def timed_output(name, delay, run_event):
    while run_event.is_set():
        time.sleep(delay)
        print name,": New Message!"


def main():
    run_event = threading.Event()
    run_event.set()
    d1 = 1
    t1 = threading.Thread(target = timed_output, args = ("bob",d1,run_event))

    d2 = 2
    t2 = threading.Thread(target = timed_output, args = ("paul",d2,run_event))

    t1.start()
    time.sleep(.5)
    t2.start()

    try:
        while 1:
            time.sleep(.1)
    except KeyboardInterrupt:
        print "attempting to close threads. Max wait =",max(d1,d2)
        run_event.clear()
        t1.join()
        t2.join()
        print "threads successfully closed"

if __name__ == '__main__':
    main()

If you REALLY need the functionality of killing a thread, use multiprocessing. It allows you to send SIGTERMs to individual "processes" (it's also very similar to the threading module). Generally speaking, threading is for when you are IO-bound, and multiprocessing is for when you are truly processor-bound.

Jason Sundram
  • 12,225
  • 19
  • 71
  • 86
Paul Seeb
  • 6,006
  • 3
  • 26
  • 38
  • 14
    With a thread's cooperation, you can kill it any way you want. Without a thread's cooperation, there is no safe way to do it and all roads lead to pain. – David Schwartz Jul 11 '12 at 15:57
  • 2
    Brilliant answer! Not exactly what I was looking for but extensive enough that I was able to adapt the logic into what I needed! Thanks for that! – Joe Jul 13 '12 at 14:01
  • 1
    I'm using a thread because I don't want an infinite while True loop. This wastes all of your CPU's time... pretty much literally. I've done something like this and without a sleep it cranks CPU% up to 100% for **seconds** at a time and with a small sleep, this only helps a little. Is there any way to do this **without** a while True? – dylnmc Oct 01 '14 at 13:47
  • 2
    @Dylan The infinite loop was only meant to offer a pithy working example. Normally one would be completing some primary task in the main loop. Still, even `time.sleep(.001)` should reduce cpu load significantly. At `time.sleep(.010)` my python thread runs with less than 1% CPU. Threads should be used for IO bound processes, or resources which need to be checked periodically. The main loop should execute your primary code, and if it needs a resource, can likely afford to sleep for 50ms to wait. If processing is truly time sensitive, you can always utilize `lock` protocols to sleep and wake. – Paul Seeb Oct 03 '14 at 06:25
  • 1
    What if the thread is blocked waiting on I/O. Does Event somehow wake it up. – user48956 Sep 19 '17 at 01:27
  • @PaulSeeb in spyder if I write keyboardinterrupt with main it works but using any funtion or main function it does not work. What can be the reason? – Imran Feb 24 '21 at 20:57
  • is it necessary to add delay? – y_159 Apr 10 '21 at 19:42
6

There are a couple of options that don't require using locks or other signals between threads. One is setting the threads as daemons, which will be killed off automatically when the main thread exits. The other is using processes instead, which have a terminate method you can call from the main process, if you needed to kill them and keep the main program running.

Both of these are especially useful if you have threads blocking on input. While using a timeout and periodically checking the signal would work in most cases without too much overhead, using daemons or processes eliminates the need for any busy loops or significant added complexity.

See the answers to this question for more details on these solutions and discussion on the problem of killing threads.

Scott Yeager
  • 61
  • 1
  • 2