【问题标题】:Get whether a blocking lock blocked获取一个阻塞锁是否被阻塞
【发布时间】:2018-08-21 07:14:14
【问题描述】:

在 Python 3 中,我想获得一个锁,然后知道它是否被阻塞。问题是threading.Lock.acquire如果用blocking=True调用总是返回True,所以在调用函数的那一刻没有办法判断锁是否已经被锁定。以这段代码为例:

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

这里的问题是lock 可以再次获取,上面代码中的注释表明存在竞争条件。

如果这是因为第三个线程在函数中的同一点首先继续并获得了锁,这是不可取的,因为它会引入轻微的延迟。确实没有理由需要保护return foo;两个线程应该可以同时做。

但是,如果获取是由于另一个线程重新计算foo,那么这是不可取的,因为一旦释放锁,foo 就会发生变化。该函数应返回调用时正在计算的foo 的值。如果foo 改变了,那么它就不能再返回那个值了。

理想情况下,我们应该有一个acquire 函数,它可以阻塞并且不管它是否阻塞仍然返回。这样,我们可以自信地断言该函数始终返回在调用该函数时正在计算的 foo 的值,并且只有当 foo 尚未被计算时,该函数才会继续,计算它,然后返回新值。这可以在 Python 中完成吗?

【问题讨论】:

  • 你试过lock.locked()吗?
  • @Sraw 嗯,不,那是什么?我在docs.python.org/3.7/library/threading.html#threading.Lock 上没有看到它。
  • 好吧,Return the status of the lock: True if it has been acquired by some thread, False if not.
  • @Sraw 这与not lock.acquire(False) 有何不同?如果锁被锁定,它不会阻塞。
  • 嗯...不,你的情况没有区别。我只是根据您的标题发表评论。诚然,我不完全理解你的描述。如果线程在计算后释放锁,foo 仍将在下次调用中重新计算。如何确定是否需要计算?也许一个普通的if foo: \n return foo 就足够了?

标签: python python-3.x multithreading thread-safety race-condition


【解决方案1】:

我知道这个问题很老,但由于我在寻找其他东西时偶然发现了它并且没有答案,所以我想我会做任何找到它的服务并回答它的人。

首先检查是否有可用的锁会导致竞争条件。您应该尝试在不检查的情况下获取锁,如下所示:

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

【讨论】:

  • 啊,是的,在计算 foo 之前检查它是否有效。我猜我三年前脑子里放了个屁。
猜你喜欢
  • 1970-01-01
  • 2020-09-16
  • 2011-04-09
  • 2017-01-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-11-13
  • 1970-01-01
相关资源
最近更新 更多