goldb.org home

AS OF MAY 2008, THIS BLOG IS NO LONGER BEING UPDATED.
Visit the new blog at: http://coreygoldberg.blogspot.com



 Monday, February 11, 2008

Python - Terminating Threads - Boolean Flag and threading.Event()

In many programming languages you can't terminate a thread directly.  Python is no different.  Rather than termintaing a thread from the code that spawned it, you just a pass a flag to the thread that tells it to terminate itself.  Typically a thread will run in a loop, periodically checking this flag so it knows if it should continue or not.  To terminate the thread from the outside, you just set its flag to die.

I was using this idiom in Python by setting a boolean flag in my spawned thread.

So a simplified thread class would look something like this:


class MyThread(threading.Thread):
    def __init__(self, num):
        threading.Thread.__init__(self)
        self.running = True
        self.num = num
        
    def stop(self):
        self.running = False
        
    def run(self):
        while self.running:
            print 'hello from thread %d' % self.num
            time.sleep(1)

I just read an old post in comp.lang.python that pointed to a recipe in the Python Cookbook that suggests using threading.Event() rather than a simple boolean flag.

So the thread class would look something like this:


class MyThread(threading.Thread):
    def __init__(self, num):
        threading.Thread.__init__(self)
        self.stop_event = threading.Event()
        self.num = num
        
    def stop(self):
        self.stop_event.set()
        
    def run(self):
        while not self.stop_event.isSet():
            print 'hello from thread %d' % self.num
            time.sleep(1)

They work exactly the same.

I am just wondering what other flexibility threading.Event() gives you, and if there is anything bad about using simple boolean checks to kill threads. I guess I will have to look it up and play around a bit.

#    Comments [5] |
Monday, February 11, 2008 8:39:36 PM (Eastern Standard Time, UTC-05:00)
Your first code is better for your use case.

Use threading.Event only if you wish to use threading.Event.wait([timeout])
Tuesday, February 12, 2008 4:43:48 AM (Eastern Standard Time, UTC-05:00)
Actually. I thought Python was relatively unusual in not allowing you to terminate threads. Both Java and C# allow it (although it is deprecated in Java)...

Michael
Tuesday, February 12, 2008 9:09:24 AM (Eastern Standard Time, UTC-05:00)
hmm.. I thought Java was the same way. At least that is how you are supposed to do it and how I always programmed threads in Java. If there is a deprecated function to do this, I wonder why it got deprecated for this other model :)

thanks for the comment.
Tuesday, February 12, 2008 1:07:41 PM (Eastern Standard Time, UTC-05:00)
Both Java and C# used to have the same problem with aborting threads. They both use the same technique - raise a ThreadAbortException (name differs in Java). You could catch this in with try...except or try...finally so that your thread could clean up (release locks and close resources) if the thread was aborted. The problem was - what if the exception was raised in the finally block - your cleanup code would be aborted.

Java handled this by deprecating aborting threads. C# (.NET) handled it by ensuring that the abort exception couldn't be raised inside a finally block. I have to say that I prefer the .NET answer.

We actually use this a great deal from IronPython (at Resolver Systems). We have a long running calculation that we need to be able to abort. It has a *very* coarse granularity in the loop it runs (which runs blocks of user code) - so we simply don't have the opportunity to look for a 'stop signal' and their are no complications with simply killing the recalc. The recalc builds a complex object tree which we use on successful completion - so interprocess communication would mean a *lot* of marshalling data backwards and forwards and so wouldn't be an efficient solution either.

We would be a bit stuck on CPython.
Tuesday, February 12, 2008 1:31:56 PM (Eastern Standard Time, UTC-05:00)
@Michael:
thanks! that is a great explanation
Comments are closed.