如何检测循环呼叫

How to detect circular calls?

本文关键字:循环 呼叫 检测 何检测      更新时间:2023-10-16

我一直在寻找死锁的原因以及避免和检测死锁的策略/工具。

另一个可能导致死锁的原因是阻塞函数以循环的方式调用其他阻塞函数,因此最终调用永远不会返回。

有时这很难发现,特别是在非常大的项目中。

那么,有没有什么工具/库/技术可以自动检测程序中的循环调用?

编辑:

我主要用C和c++编写代码,所以,如果可能的话,给出适用于这些语言的主题的任何信息。

然而,这个话题似乎在SO中几乎没有涉及,所以其他语言的答案也可以。尽管如果有人发现相关的话,这些可能值得单独讨论

谢谢。

尝试获取相同的不可重入锁的循环(或递归)调用是最容易调试的阻塞场景之一:锁是确定性的,可以很容易地检查。当应用程序锁定时,启动调试器并查看堆栈跟踪,以了解持有哪些锁及其原因。

关于锁问题的一般解决方案…您可以查看一些提供互斥锁排序的库,并在尝试锁定无序互斥锁时检测。这种类型的解决方案可能是复杂的正确实施,但是一旦到位确保你不能进入死锁状态,因为它迫使所有进程获得锁在同一顺序(即如果持有锁拉过程,和它试图获取锁磅的顺序是正确的,那么它可以成功或锁,但无论过程持有锁磅不能试图锁拉排序约束不满足)。

如果你在Linux上,有两个Valgrind工具用于检测死锁和竞争条件:Helgrind, DRD。它们都是相互补充的,并且它们都值得检查线程错误。

在linux中你可以使用valgrind来检测死锁,使用--tool=helgrind

检测死锁(IMO)的最佳方法是编写一个测试程序,在30个不同线程中随机调用所有函数10000次。

如果你得到一个死锁,你可以使用VS2010的"并行堆栈"窗口。调试并行堆栈
->窗口->这个窗口将显示所有栈,这样您就可以找到死锁的方法。

我用来编写线程安全对象的一个简单策略:
线程安全的对象在调用其公共方法时应该是安全的,因此在使用它时不会出现死锁。

所以,我们的想法是锁定所有访问对象数据的公共方法。
除此之外,您还需要确保在类代码中永远不会调用公共方法。如果需要使用其中一个公共方法,那么将该方法设为私有,并将该私有方法包装为一个公共方法,该公共方法锁定并调用该方法。

如果你想要更好的锁粒度,你可以为每个部分创建有自己锁的对象,并像我建议的那样锁定它。然后使用封装将这些类组合成一个类。

的例子:

class Blah {
  MyData data;
  Lock lock;
public:
  DataItem GetData(int index)
  { 
     ReadLock read(lock);
     return LocalGetData(index);
  }
  DataItem FindData(string key)
  {
     ReadLock read(lock);
     DataItem item;
     //find the item, can use LocalGetData() to get the item without deadlocking
     return item;
  }
  void PutData(DataItem item)
  {
    ReadLock write(lock); 
    //put item in database
  }
private:
  DataItem LocalGetData(int index)
  {
    return data[index];
  }
} 

您可以找到一个构建调用图的工具,并检查图中的循环。

否则,有许多策略可以检测死锁或其他循环,但它们都依赖于某种支持基础设施。

存在死锁避免策略,必须分配锁优先级并根据优先级对锁进行排序。但是,这需要更改代码并执行标准。