48

I'm looking to terminate some threads after a certain amount of time. These threads will be running an infinite while loop and during this time they can stall for a random, large amount of time. The thread cannot last longer than time set by the duration variable. How can I make it so after the length set by duration, the threads stop.

def main():
    t1 = threading.Thread(target=thread1, args=1)
    t2 = threading.Thread(target=thread2, args=2)

    time.sleep(duration)
    #the threads must be terminated after this sleep
Qantas 94 Heavy
  • 15,750
  • 31
  • 68
  • 83
Takkun
  • 8,119
  • 13
  • 38
  • 41
  • Is your thread going to be blocking? – Nix Jun 29 '11 at 17:02
  • The threads will be running in an infinite loop. There is a possibility that the threads will sleep for a random amount of time. The threads absolutely cannot run over the duration specified at the start of the program. If the threads do not no how much time they spent asleep, how will they know when to end. – Takkun Jun 29 '11 at 17:19
  • 21
    Would somebody please just answer his question without demanding that he tilt his entire world on its axis. There are other programmers out there like myself who need an answer to this question, and they absolutely, positively can not do it any other way (yet). – puk Oct 16 '13 at 03:07

4 Answers4

108

This will work if you are not blocking.

If you are planing on doing sleeps, its absolutely imperative that you use the event to do the sleep. If you leverage the event to sleep, if someone tells you to stop while "sleeping" it will wake up. If you use time.sleep() your thread will only stop after it wakes up.

import threading
import time

duration = 2

def main():
    t1_stop = threading.Event()
    t1 = threading.Thread(target=thread1, args=(1, t1_stop))

    t2_stop = threading.Event()
    t2 = threading.Thread(target=thread2, args=(2, t2_stop))

    time.sleep(duration)
    # stops thread t2
    t2_stop.set()

def thread1(arg1, stop_event):
    while not stop_event.is_set():
        stop_event.wait(timeout=5)

def thread2(arg1, stop_event):
    while not stop_event.is_set():
        stop_event.wait(timeout=5)
meisterluk
  • 804
  • 10
  • 19
Nix
  • 57,072
  • 29
  • 149
  • 198
  • Is the `time` in `stop_event.wait(time)` supposed to be a numeric variable like `1` or is it the `time` module as in `import time`? It seems weird to use a module like that so I'm just checking. – mdw7326 Mar 01 '16 at 22:47
  • 2
    Found this on Google and had the same question so decided I would contribute. it is fractions of a second. So `stop_event.wait(1)` is 1 second. – std''OrgnlDave Dec 25 '16 at 15:55
  • This is a perfect answer to a perfect question. Both are extremely concise, accessible, and generalizable, and yet they both communicate substantial complexity. Well done. – synaptik Mar 15 '17 at 02:36
11

If you want the threads to stop when your program exits (as implied by your example), then make them daemon threads.

If you want your threads to die on command, then you have to do it by hand. There are various methods, but all involve doing a check in your thread's loop to see if it's time to exit (see Nix's example).

Community
  • 1
  • 1
Seth
  • 45,033
  • 10
  • 85
  • 120
1

If you want to use a class:

from datetime import datetime,timedelta

class MyThread(): 

    def __init__(self, name, timeLimit):        
        self.name = name
        self.timeLimit = timeLimit
    def run(self): 
        # get the start time
        startTime = datetime.now()
    
        while True:
           # stop if the time limit is reached :
           if((datetime.now()-startTime)>self.timeLimit):
               break
           print('A')

mt = MyThread('aThread',timedelta(microseconds=20000))
mt.run()
Barnik Biswas
  • 354
  • 3
  • 8
Nora_F
  • 431
  • 5
  • 17
0

An alternative is to use signal.pthread_kill to send a stop signal. While it's not as robust as @Nix's answer (and I don't think it will work on Windows), it works in cases where Events don't (e.g., stopping a Flask server).

test.py

from signal import pthread_kill, SIGTSTP
from threading import Thread

import time

DURATION = 5


def thread1(arg):
    while True:
        print(f"processing {arg} from thread1...")
        time.sleep(1)


def thread2(arg):
    while True:
        print(f"processing {arg} from thread2...")
        time.sleep(1)


if __name__ == "__main__":
    t1 = Thread(target=thread1, args=(1,))
    t2 = Thread(target=thread2, args=(2,))

    t1.start()
    t2.start()
    time.sleep(DURATION)
    # stops all threads
    pthread_kill(t2.ident, SIGTSTP)

result

$ python test.py
processing 1 from thread1...
processing 2 from thread2...
processing 1 from thread1...
processing 2 from thread2...
processing 1 from thread1...
processing 2 from thread2...
processing 1 from thread1...
processing 2 from thread2...
processing 1 from thread1...
processing 2 from thread2...

[19]+  Stopped                 python test.py
reubano
  • 5,087
  • 1
  • 42
  • 41