So, I've got a multithreaded python program, which is currently suffering from deadlock. I was going to log lock acquiring by subclassing threading.Lock objects:
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)
When I try to run the program, I get the following error:
class DebugLock(threading.Lock):
TypeError: Error when calling the metaclass bases
cannot create 'builtin_function_or_method' instances
So, my question is twofold:
Is it possible to subclass Lock objects to do what I'm doing?
If not, what is the best way to debug deadlock in python?
Note: I'm not writing any Python extension. There's a similar question: How to debug deadlock with python? However, it deals with compiling C++ code and using GDB, which I can't do since my code is pure python.
A lock can be locked using the acquire() method. Once a thread has acquired the lock, all subsequent attempts to acquire the lock are blocked until it is released. The lock can be released using the release() method.
A Lock object can not be acquired again by any thread unless it is released by the thread which is accessing the shared resource. An RLock object can be acquired numerous times by any thread. A Lock object can be released by any thread. An RLock object can only be released by the thread which acquired it.
The thread lock is used to prevent the race condition. The thread lock locks access to a shared variable when used by one thread so that any other thread cannot access it and then removes the lock when the thread is not using the shared variable so that the variable is available to other threads for processing.
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'
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> >>>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With