How to stop a looping thread in Python? How to stop a looping thread in Python? python python

How to stop a looping thread in Python?


Threaded stoppable function

Instead of subclassing threading.Thread, one can modify the function to allowstopping by a flag.

We need an object, accessible to running function, to which we set the flag to stop running.

We can use threading.currentThread() object.

import threadingimport timedef doit(arg):    t = threading.currentThread()    while getattr(t, "do_run", True):        print ("working on %s" % arg)        time.sleep(1)    print("Stopping as you wish.")def main():    t = threading.Thread(target=doit, args=("task",))    t.start()    time.sleep(5)    t.do_run = False    if __name__ == "__main__":    main()

The trick is, that the running thread can have attached additional properties. The solution buildson assumptions:

  • the thread has a property "do_run" with default value True
  • driving parent process can assign to started thread the property "do_run" to False.

Running the code, we get following output:

$ python stopthread.py                                                        working on taskworking on taskworking on taskworking on taskworking on taskStopping as you wish.

Pill to kill - using Event

Other alternative is to use threading.Event as function argument. It is bydefault False, but external process can "set it" (to True) and function canlearn about it using wait(timeout) function.

We can wait with zero timeout, but we can also use it as the sleeping timer (used below).

def doit(stop_event, arg):    while not stop_event.wait(1):        print ("working on %s" % arg)    print("Stopping as you wish.")def main():    pill2kill = threading.Event()    t = threading.Thread(target=doit, args=(pill2kill, "task"))    t.start()    time.sleep(5)    pill2kill.set()    t.join()

Edit: I tried this in Python 3.6. stop_event.wait() blocks the event (and so the while loop) until release. It does not return a boolean value. Using stop_event.is_set() works instead.

Stopping multiple threads with one pill

Advantage of pill to kill is better seen, if we have to stop multiple threadsat once, as one pill will work for all.

The doit will not change at all, only the main handles the threads a bit differently.

def main():    pill2kill = threading.Event()    tasks = ["task ONE", "task TWO", "task THREE"]    def thread_gen(pill2kill, tasks):        for task in tasks:            t = threading.Thread(target=doit, args=(pill2kill, task))            yield t    threads = list(thread_gen(pill2kill, tasks))    for thread in threads:        thread.start()    time.sleep(5)    pill2kill.set()    for thread in threads:        thread.join()


This has been asked before on Stack. See the following links:

Basically you just need to set up the thread with a stop function that sets a sentinel value that the thread will check. In your case, you'll have the something in your loop check the sentinel value to see if it's changed and if it has, the loop can break and the thread can die.


I read the other questions on Stack but I was still a little confused on communicating across classes. Here is how I approached it:

I use a list to hold all my threads in the __init__ method of my wxFrame class: self.threads = []

As recommended in How to stop a looping thread in Python? I use a signal in my thread class which is set to True when initializing the threading class.

class PingAssets(threading.Thread):    def __init__(self, threadNum, asset, window):        threading.Thread.__init__(self)        self.threadNum = threadNum        self.window = window        self.asset = asset        self.signal = True    def run(self):        while self.signal:             do_stuff()             sleep()

and I can stop these threads by iterating over my threads:

def OnStop(self, e):        for t in self.threads:            t.signal = False