Python如何判断当前线程是否持有锁
我有一个叫做 threading.Lock
的对象,我想知道当前的线程(也就是正在运行的程序部分)是否正在持有这个锁。有什么简单的方法可以做到这一点呢?
4 个回答
请看看这个链接:线程同步机制
你可以试试下面这个:
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
希望这对你有帮助
在Python 3.9.5中,如果你想知道一个RLock
对象的拥有线程,可以这样做:
如果是为了调试,你可以直接打印这个锁,输出的内容大概是这样的:
<unlocked _thread.RLock object owner=0 count=0 at 0x7f77467d1030>
你可以看看
owner
属性,它里面包含了拥有这个锁的线程的ID。如果想通过代码获取拥有者的值:(注意:这个方法依赖于具体的实现,未来版本可能会失效;另外要注意,在你检查拥有者和实际使用这个信息之间可能会有竞争条件)
这取决于Python是用Python的实现,还是用C的实现。
In [12]: threading._CRLock() # this is a recursive lock implemented in C Out[12]: <unlocked _thread.RLock object owner=0 count=0 at 0x7f7746878cc0> In [13]: threading._PyRLock() # this is a recursive lock implemented in Python Out[13]: <unlocked threading._RLock object owner=None count=0 at 0x7f7746764cd0>
下面的方法只在实现是Python的时候有效。
你只需要访问
_owner
属性:threading._PyRLock()._owner
关于release
方法的帮助说明:
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
,那么这个锁仍然会被那个线程持有,其他线程就无法获取这个锁。
我所知道的,使用 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
但实际上,你的代码其实不应该需要这样做。你为什么觉得需要这个明确的检查呢?通常在写一段代码时,你应该知道在这个上下文中锁是否已经被获取。你能分享一个你觉得需要检查的例子吗?