Python Threading Lock Example

There are a number of ways to implement a lock, but one of the easiest is just to subclass threading.Thread and add an attribute that references the lock.

The example below shows a threading lock that is used to synchronize printing. When the print functions aren’t coordinated, multiple threads may try to print at the same time, resulting in garbled output. For instance, in this program, the line breaks are sometimes interleaved incorrectly when the lock is taken out:

Hi, I'm Thread-3 and I'm done processing! Value=3
Hi, I'm Thread-1 and I'm done processing! Value=7Hi, I'm Thread-4 and I'm done processing! Value=1
Hi, I'm Thread-2 and I'm done processing! Value=9
Hi, I'm Thread-3 and I'm done processing! Value=16
Hi, I'm Thread-4 and I'm done processing! Value=0
Hi, I'm Thread-3 and I'm done processing! Value=9

Hi, I'm Thread-4 and I'm done processing! Value=0

Incorrect line breaks while printing to stdout is usually not terribly dire, but failing to synchronize threads during other I/O applications can corrupt data and lead to disastrous results.

Now, as promised, here’s an example that implements a simple lock to synchronize printing among threads:

from __future__ import print_function
import threading
from random import randint

class LockingThread(threading.Thread):
        def __init__(self, lock, *args, **kwargs):
                super(LockingThread, self).__init__(*args, **kwargs)
                self.lock = lock

def do_some_work():
        '''Placeholder for doing some actual, important computation'''
        return randint(0,10)**randint(1000,10000) % 20

def output_results():
        current_thread = threading.current_thread()
        for i in xrange(0,100):
                value = do_some_work()
                with current_thread.lock:
                    print("Hi, I'm {0} and I'm done processing! Value={1}"\
                                        .format(current_thread.name, value))

if __name__=='__main__':
        num_threads = 4
        the_lock = threading.Lock()
        for i in xrange(0, num_threads):
                LockingThread(the_lock, target=output_results).start()

With the lock in place, all of the printing goes smoothly, resulting in nice, clean output like this:

Hi, I'm Thread-2 and I'm done processing! Value=0
Hi, I'm Thread-1 and I'm done processing! Value=5
Hi, I'm Thread-2 and I'm done processing! Value=1
Hi, I'm Thread-2 and I'm done processing! Value=12
Hi, I'm Thread-2 and I'm done processing! Value=4
Hi, I'm Thread-2 and I'm done processing! Value=0
Hi, I'm Thread-2 and I'm done processing! Value=9

A few comments on the code:

  • The basic flow of the program is this:  Spawn a few threads (the part under __main__) and have them do some operation (the  do_some_work() function).
  • The lock’s “with” statement acquires and releases the lock. It’s equivalent to calling lock.acquire() before the print statement, and then lock.release() after the print statement has completed.
  • The program imports print from __future__ because Python 2’s print statement isn’t thread safe, even if you put it inside a lock.  Most of the time everything works fine, but occasionally you’ll get extra line breaks.  The new print function introduced in Python 3 doesn’t seem to have this problem, so as long as you import from __future__ everything works as expected.
If you liked this post, say thanks by sharing it:

Also read...

Leave a Reply

Your email address will not be published. Required fields are marked *