Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to subclass Lock() objects in Python? If not, other ways to debug deadlock?

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:

  1. Is it possible to subclass Lock objects to do what I'm doing?

  2. 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.

like image 789
jmite Avatar asked Jul 21 '11 18:07

jmite


People also ask

How do you implement a lock in 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.

What are lock objects in Python?

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.

How does Python thread lock work?

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.


2 Answers

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'
like image 43
Jeremy Brown Avatar answered Oct 08 '22 09:10

Jeremy Brown


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>
    >>>
like image 86
Russ Avatar answered Oct 08 '22 11:10

Russ