【发布时间】: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