RLock中的线程块

时间:2016-02-27 11:11:17

标签: python multithreading deadlock

我有这个实现:

def mlock(f):
    '''Method lock. Uses a class lock to execute the method'''
    def wrapper(self, *args, **kwargs):
        with self._lock:
            res = f(self, *args, **kwargs)
        return res
    return wrapper


class Lockable(object):

    def __init__(self):
        self._lock = threading.RLock()

我在几个地方使用,例如:

class Fifo(Lockable):

    '''Implementation of a Fifo. It will grow until the given maxsize; then it will drop the head to add new elements'''

    def __init__(self, maxsize, name='FIFO', data=None, inserted=0, dropped=0):
        self.maxsize = maxsize
        self.name = name
        self.inserted = inserted
        self.dropped = dropped
        self._fifo = []
        self._cnt = None
        Lockable.__init__(self)
        if data:
            for d in data:
                self.put(d)

    @mlock
    def __len__(self):
        length = len(self._fifo)
        return length

    ...

应用程序非常复杂,但效果很好。为了确保,我一直在对正在运行的服务进行压力测试,我发现它有时(很少)在mlock中出现死锁。我假设另一个线程持有锁而不释放它。我该怎么调试呢?请注意:

  • 很难重现:我需要几个小时的测试来解决僵局
  • 应用程序在后台运行
  • 一旦陷入僵局,我再也无法与之互动

我想知道:

  • 什么线程持有锁?
  • 为什么不被释放?我正在使用上下文管理器来获取锁,因此应该始终释放它。臭虫在哪里?!

我还有哪些选项可以进一步调试?

我一直在检查是否有任何方法可以知道什么线程持有RLock,但似乎没有API。

1 个答案:

答案 0 :(得分:1)

我认为这不是一个简单的解决方案,但可以通过一些工作完成。

就个人而言,我发现以下内容很有用(尽管在C ++中)。

首先创建一个使用曲目线程的Lockable基础'与它的互动。 Lockable对象将使用一个额外的(非递归)锁来保护字典映射线程ID与它的交互:

  • 当一个线程试图锁定时,它(锁定和)会创建一个条目。
  • 获取锁定时,它(锁定并)修改该条目。
  • 当它释放锁时,它(锁定并)删除该条目。

此外,Lockable对象将具有低优先级线程,很少唤醒(每隔几分钟一次),并查看是否有死锁指示(由事件表示近似)线程长时间持有锁,而至少有一个其他线程等待它。)

因此,线程的条目应包括:

问题是这可能会改变线程的相对时间,这可能会导致程序进入与通常不同的执行路径。

在这里,你需要发挥创意。您可能还需要在这些(可能还有其他)操作中引发(随机)时间流逝。