【问题标题】:Thread blocks in an RLockRLock 中的线程块
【发布时间】:2016-06-10 16:30:01
【问题描述】:

我有这个实现:

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。

【问题讨论】:

    标签: python multithreading deadlock


    【解决方案1】:

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

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

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

    • 当线程尝试锁定时,它(锁定并)创建一个条目。
    • 当它获得锁时,它(锁定并)修改条目。
    • 当它释放锁时,它(锁定并)删除条目。

    此外,Lockable 对象将有一个低优先级线程,很少醒来(每几分钟一次),并查看是否有死锁迹象(近似于线程持有锁的事件很长一段时间,而至少有一个其他线程在等待它)。

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


    问题在于,这可能会改变线程的相对时间,这可能会导致您的程序进入与正​​常情况不同的执行路径。

    在这里你需要发挥创造力。您可能还需要在这些(可能还有其他)操作中引入(随机)时间间隔。

    【讨论】:

      猜你喜欢
      • 2017-04-22
      • 1970-01-01
      • 1970-01-01
      • 2021-10-24
      • 2016-10-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-01-02
      相关资源
      最近更新 更多