可以在Python中子类化Lock()对象吗?如果不可以,还有什么方法调试死锁?
我有一个多线程的Python程序,现在遇到了死锁的问题。我本来打算通过子类化`threading.Lock`对象来记录锁的获取情况:
import traceback
class DebugLock(threading.Lock):
def acquire(self):
print >>sys.stderr, "acquired", self
#traceback.print_tb
threading.Lock.acquire(self)
def release(self):
print >>sys.stderr, "released", self
#traceback.print_tb
threading.Lock.release(self)
但是当我尝试运行这个程序时,出现了以下错误:
class DebugLock(threading.Lock):
TypeError: Error when calling the metaclass bases
cannot create 'builtin_function_or_method' instances
所以,我的问题有两个:
我能否对子类化Lock对象来实现我想做的事情?
如果不能,调试Python中的死锁最好的方法是什么?
注意:我并没有编写任何Python扩展。有一个类似的问题:如何调试Python中的死锁?不过那个问题涉及到编译C++代码和使用GDB,而我不能这样做,因为我的代码是纯Python。
3 个回答
3
如果你想实现类似于继承的功能,但又不想遇到这个错误,我建议你试试下面的方法。
import traceback
from threading import Lock
class DebugLock():
def __init__(self,lock = None):
self.lock = lock or Lock()
# normally done with __dict__
for command in dir(self.lock):
self.__dict__[command] = getattr(self.lock,command)
我通常用 self.__dict__.update(lock.__dict__)
这个方法,但似乎不太管用。我用锁定的代码测试了一下
X = DebugLock()
y = X.lock
Y = DebugLock(y)
X.acquire()
Y.acquire()
X.release()
Y.release()
结果程序卡住了,所以我觉得这个方法是有效的。
5
Russ回答了一个重要的问题(问题#2),我来回答问题#1。
看起来这是不可能的。threading.Lock() 是一个工厂函数(文档)。它会调用 thread.allocate_lock(),而且我们无法控制 Lock 对象的创建。你也不能随便修改 thread.LockType 类的定义(这个类的框架在 thread.pi 中暴露出来)。
>>> thread.LockType.foo = "blah"
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: can't set attributes of built-in/extension type 'thread.lock'
19
你可以使用“有一个锁”和“是一个锁”的方法,像这样:
import threading, traceback, sys
class DebugLock(object):
def __init__(self):
self._lock = threading.Lock()
def acquire(self):
print("acquired", self)
#traceback.print_tb
self._lock.acquire()
def release(self):
print("released", self)
#traceback.print_tb
self._lock.release()
def __enter__(self):
self.acquire()
def __exit__(self, type, value, traceback):
self.release()
在这里,我加入了合适的上下文保护,因为你可能想要在使用锁的时候用with
语法(谁不想呢?)。
下面是使用示例:
>>> lock = DebugLock() >>> with lock: ... print("I'm atomic!") ... acquired <__main__.DebugLock object at 0x7f8590e50190> I'm atomic! released <__main__.DebugLock object at 0x7f8590e50190> >>>