Python thread locks vs forced timer delays

718 views Asked by At

Its my understanding that when you implement a global lock in Python, this should reserve stdout for the thread that activates the lock, and therefore prevent other threads from utilizing stdout until the thread releases the lock.

Doesn't this means that in the following code, the loop in thread "a" should complete before the function in thread "b" outputs anything? When I run it, the "7" that thread "c" prints is sometimes interleaved in the output of "a".

I'd expect the output to always be the following:

 5
 5
 5
 5
 5
 6
 7

But I am getting:

 5
 7
 5
 5
 5
 6

The code:

import threading, time

thelock = threading.Lock()

def afunc(var):
    with thelock:
        for i in range(5):
            time.sleep(.0002)
            print(var)

def bfunc(var):
    print(var)

a=threading.Thread(target=afunc, args=(5,))
b=threading.Thread(target=bfunc, args=(6,))
c=threading.Thread(target=bfunc, args=(7,))
a.start()
b.start()
c.start()

This is with Python 3.4.3 in OS X 10.10.3. The same behavior occurs when running the file directly in the OS X Terminal, or within PyCharm 4.5.1.

2

There are 2 answers

1
John On BEST ANSWER

You are not implementing the global lock because there is no such thing. I mean, there is but that is Global Interpreter Lock which is language feature and you are not implementing that.

GIL: http://en.wikipedia.org/wiki/Global_Interpreter_Lock

Now, about the lock which you are implementing:

threading.Lock() - A factory function that returns a new primitive lock object. Once a thread has acquired it, subsequent attempts to acquire it block, until it is released; any thread may release it.

See official docs for threading: https://docs.python.org/2/library/threading.html

Generally speaking, when you lock some resource into critical section, this resource will be locked only for threads which must also acquire lock to access the shared resource. In your example, function b does not attempt to acquire lock before writing to stdout.

Besides, i am fairly certain that this won't work as you expect and output will be mixed up anyway, as the stdout doesn't get locked. To get clean output, you could have threads passing messages to some thread-safe shared queue, and then have only one thread write to stdout from that queue.

2
textshell On

threading.Lock does not influence the use of standard output at all. It only serves to create what called critical sections where only one thread at a time may execute code in all critical sections protected by the same lock instance.

If you need to serialize output you have to implement that yourself, maybe based on locks or some other mechanism.

For example you could have a logging class that buffers the logging of other threads while some locks are held, but that is not trivial because the logging class can't just "check" if a certain lock is in use because the would lead to race conditions. Generally blocking logging isn't such a great idea. But maybe you're thinking about some other use of stdout. Usually if you are trying to generate a specific stdout in a multithreaded program it is likely that you should explicitly use a lock for all output or restrict usage of output to just one thread. For restricting output to one thread maybe queue.Queue can help so multiple threads can produce complete parts that are then printed by one thread a part at a time.