可以在Python中子类化Lock()对象吗?如果不可以,还有什么方法调试死锁?

11 投票
3 回答
3482 浏览
提问于 2025-04-16 22:01

我有一个多线程的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  

所以,我的问题有两个:

  1. 我能否对子类化Lock对象来实现我想做的事情?

  2. 如果不能,调试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>
    >>>

撰写回答