我有一个 threading.Lock
对象,我想知道当前线程是否持有这个锁。最简单的方法是什么?
我有一个 threading.Lock
对象,我想知道当前线程是否持有这个锁。最简单的方法是什么?
我不知道有没有直接使用 threading.Lock
对象实现此目的的方法。虽然这些对象具有 locked
属性,但该属性在所有线程中都会显示为 True
,而不仅仅是拥有者线程。如果使用 RLock
,那么可以完成此操作,但必须访问 RLock 对象上的内部 __owner
属性,这并不可取且不能保证始终有效。以下是实现此目的的代码:
#!/usr/bin/python
import threading
import time
def worker():
if l._RLock__owner is threading.current_thread():
print "I own the lock"
else:
print "I don't own the lock"
l.acquire()
if l._RLock__owner is threading.current_thread():
print "Now I own the lock"
else:
print "Now I don't own the lock"
time.sleep(5)
l.release()
if __name__ == "__main__":
l = threading.RLock()
thds = []
for i in range(0, 2):
thds.append(threading.Thread(target=worker))
thds[i].start()
for t in thds:
t.join()
以下是输出结果:
dan@dantop:~> ./test.py
I don't own the lock
Now I own the lock
I don't own the lock
但实际上,你的代码真的不应该这样做。为什么你觉得需要进行这种显式检查呢?通常情况下,在编写代码块时,您知道在该上下文中是否已获取锁定。你能分享一个例子,让我们看看你认为需要检查它吗?
RLock
的方法在 Python 3 中不起作用(实际上,因为它使用了一个未记录的特性,所以它可能会在任何新版本中出现问题)。 - user202729release
方法的帮助文本:
Help on built-in function release:
release(...)
release()
Release the lock, allowing another thread that is blocked waiting for
the lock to acquire the lock. The lock must be in the locked state,
but it needn't be locked by the same thread that unlocks it.
Lock
对象不在乎是哪个线程锁定了它们,因为任何线程都可以解锁它们。因此,对于未经修改的锁对象,没有办法确定当前线程是否持有锁,因为没有线程“持有”锁 - 它只是已被锁定或未被锁定。def a():
with theLock:
do_stuff()
b()
do_other_stuff()
def b():
with theLock:
do_b_stuff()
在这里,你只想在b()
中获取theLock
,如果线程还没有持有锁。就像我在评论中提到的那样,这是重入锁的一个完美用例。如果你像这样创建锁:
theLock = threading.RLock()
a()
时,它会获取锁。然后在 b()
中,它允许您重新获取锁而不会有任何问题。此外,如果您使用上下文管理器语法 (with theLock:
),则无需担心其中的一个注意事项。acquire
和release
,则需要确保每次调用acquire
都要相应地调用一次release
。 在上面的示例中,如果我在a()
和b()
中都调用了theLock.acquire()
,那么我也需要在两个函数中调用release()
。 如果您调用acquire
两次,但只调用release
一次,则该线程仍将持有该锁,使其他线程不能获取该锁。import threading
lock = threading.Lock()
lock.acquire()
#now that the lock is taken, using lock.acquire(False) will return False
if not lock.acquire(False):
# could not lock the resource
现在给这个加点变化:
import threading
class customLock(object):
_accessLock = threading.Lock()
def __init__(self):
self._lock = threading.Lock()
self.ownerThread = None
def acquire(self, thread):
self._accessLock.acquire()
try:
if self._lock.acquire():
self.ownerThread = thread
finally:
self._accessLock.release()
def release(self):
self._accessLock.acquire()
try:
self._lock.release()
self.ownerThread = None
finally:
self._accessLock.release()
def getOwner(self):
return self.ownerThread
def acquire(self, blocking=True):
return self._lock.acquire(blocking)
将初始示例转换为:
import threading
lock = customLock()
lock.acquire(threading.current_thread())
#now that the lock is taken, using lock.acquire(False) will return False
if not lock.acquire(False):
# could not lock the resource
if lock.getOwner() is threading.current_thread():
# do something
RLock
对象的所有者线程:
调试目的:您可以简单地打印锁定状态,输出将类似于
<unlocked _thread.RLock object owner=0 count=0 at 0x7f77467d1030>
查看owner
属性,其中包含所有者线程的线程ID。
以编程方式获取所有者的值:警告:使用实现细节,可能在未来版本中会出现问题;还要注意,在检查所有者和实际使用信息之间可能存在竞争条件
这取决于Python是使用Python实现还是C实现。
In [12]: threading._CRLock() # 这是一个在C中实现的递归锁
Out[12]: <unlocked _thread.RLock object owner=0 count=0 at 0x7f7746878cc0>
In [13]: threading._PyRLock() # 这是一个在Python中实现的递归锁
Out[13]: <unlocked threading._RLock object owner=None count=0 at 0x7f7746764cd0>
以下方法仅在实现为Python时有效。
只需访问_owner
属性:
threading._PyRLock()._owner
Lock
对象包装起来以保留信息。请参见multithreading - Is it possible to subclass Lock() objects in Python? If not, other ways to debug deadlock? - Stack Overflow。 - user202729