ActiveState Code

Recipe 65448: Thread Control Idiom


This is a basic idiom I use on almost every thread I write.

Python
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
#!/usr/bin/env python
"""
testthread.py
An example of an idiom for controling threads

Doug Fort
http://www.dougfort.net
"""

import threading

class TestThread(threading.Thread):
    """
    A sample thread class
    """
        
    def __init__(self):
        """
        Constructor, setting initial variables
        """
        self._stopevent = threading.Event()
        self._sleepperiod = 1.0

        threading.Thread.__init__(self, name="TestThread")
        
    def run(self):
        """
        overload of threading.thread.run()
        main control loop
        """
        print "%s starts" % (self.getName(),)
        
        count = 0
        while not self._stopevent.isSet():
            count += 1
            print "loop %d" % (count,)
            self._stopevent.wait(self._sleepperiod)
        
        print "%s ends" % (self.getName(),)

    def join(self,timeout=None):
        """
        Stop the thread
        """
        self._stopevent.set()
        threading.Thread.join(self, timeout)

if __name__ == "__main__":
    testthread = TestThread()
    testthread.start()
    
    import time
    time.sleep(10.0)

    testthread.join()
    

Discussion

It is based on using threading.Event to control the main thread loop. This gives the ability to pause the thread with Event.wait(), but to break out from join() (or wherever) without waiting for the timer to expire.

Comments

  1. 1. At 10:16 a.m. on 6 jul 2002, Norbert Klamann said:

    This one works on Win NT.

  2. 2. At 3:31 p.m. on 7 jun 2007, Noah Spurrier said:

    Why do you call threading.Thread.join(self, timeout) instead of just calling self.join(timeout)? Why do you call threading.Thread.join(self, timeout) instead of just calling self.join(timeout) ? I use almost exactly the same idiom for trivial treads, but I have a generic thread looper that will run a loop on any given function:

    #!/usr/bin/env python
    
    import time
    import threading
    
    class thread_looper (threading.Thread):
        def __init__ (self, interval, function, args=[], kwargs={}):
            threading.Thread.__init__(self)
            self.interval = interval
            self.function = function
            self.args = args
            self.kwargs = kwargs
            self.finished = threading.Event()
        def stop (self):
            self.finished.set()
            self.join()
        def run (self):
            while not self.finished.isSet():
                self.finished.wait(self.interval)
                self.function(*self.args, **self.kwargs)
    
    def my_function (a, b, c):
        print "meaningless arguments as an example:", a, b, c
        print time.asctime()
    
    print "Calling my_function() in a thread every 1/10th of second for two seconds."
    t = thread_looper (0.1, my_function, (1,0,-1))
    t.start()
    # The thread, t, runs while we are asleep.
    time.sleep(2)
    t.stop()
    print "Done!"
    

Sign in to comment