简体   繁体   中英

Get whether a blocking lock blocked

In Python 3, I want to acquire a lock and then know whether it blocked or not. The problem is that threading.Lock.acquire always returns True if it is called with blocking=True , so there is no way to tell whether the lock was already locked at the moment when the function was called. Take this code for example:

import threading

foo = None
lock = threading.Lock()

def bar():
    global foo
    # Only compute foo in one thread at a time.
    if not lock.acquire(blocking=False):
        # The race condition exists here.
        # Another thread is already computing foo.
        # This instance does not need to recompute foo.
        # Wait for that instance to finish.
        with lock:
            # Just return the value that the other instance computed.
            return foo
    # No other instance of this function is computing foo.
    with lock:
        # Compute foo.
        foo = [something]
        return foo

The problem here is that lock can be acquired again where a comment in the code above says that a race condition exists.

If this is because a third thread is at the same point in the function continued first and acquired the lock, this is undesirable because it introduces a slight delay. There really is no reason that return foo needs to be protected; two threads should be able to do it at the same time.

However, if the acquire is due to another thread recomputing foo , then this is undesirable because foo will have changed once the lock is released. The function should return the value of foo that was being computed when it was called. If foo changes, then it cannot return that value anymore.

Ideally, we would have an acquire function that can block and still return whether it blocked or not. That way, we can confidently assert that the function always returns the value of foo that was being computed when the function was called and that only if foo was not already being computed does the function then go ahead, compute it, and return the new value. Can this be done in Python?

I know this question is old, but since I stumbled on it while looking for something else and it is unanswered, I figured I'd do anyone who finds it a service and answer it.

You are causing the race condition by first checking if a lock is available. You should try acquiring the lock without checking, like so:

import threading

foo = None
lock = threading.Lock()

def bar():
    global foo
    # Only compute foo in one thread at a time.
    with lock:
        # Only compute foo once.
        if foo is None:
            foo = [something]
        # Just return the value that is now guaranteed to be computed.
        return foo

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM