Is it possible to subclass Lock() objects in Python? If not, other ways to debug deadlock?
You could just use the "has a lock" versus "is a lock" approach, like so:
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()
where I've thrown in the appropriate context guards since you likely want to use the with
syntax with your locks (who wouldn't?).
Usage shown below:
>>> lock = DebugLock() >>> with lock: ... print("I'm atomic!") ... acquired <__main__.DebugLock object at 0x7f8590e50190> I'm atomic! released <__main__.DebugLock object at 0x7f8590e50190> >>>
Russ answered the important question (#2), I'll answer question #1.
Doesn't appear to be possible. threading.Lock() is a factory function (documentation). It calls thread.allocate_lock() - there's no control over Lock object creation. You also cannot monkeypatch the thread.LockType class definition (the class skeleton exposed in 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'
If you want to do something like inheritance without running into this error, I suggest you try
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)
My normal method of using self.__dict__.update(lock.__dict__)
doesn't seem to be working. I tested this out with the locking code
X = DebugLock()
y = X.lock
Y = DebugLock(y)
X.acquire()
Y.acquire()
X.release()
Y.release()
and that hangs, so I think it is working.