如何检测循环调用?

发布于 2024-12-02 12:46:36 字数 327 浏览 0 评论 0原文

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

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

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

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

编辑: 我主要使用 C 和 C++ 编写代码,因此,如果可能的话,请提供有关适用于这些语言的主题的任何信息。

尽管如此,似乎这个主题几乎没有在 SO 中涵盖,所以其他语言的答案也可以。 尽管如果有人认为相关,也许这些应该有一个自己的主题

谢谢。

I've been looking for causes for deadlocks and strategies/tools to avoid and detect them.

Another potential cause for deadlocks is to have blocking functions calling other blocking functions in a circular way, so that eventually a call never returns.

Sometimes this is hard to discover, specially in very large projects.

So, are there any tools/libraries/techiques that allow to automate the detection of circular calls in a program?

EDIT:
I code mostly in C and C++ so, if possible, give any information about the topic that is applicable to those languages.

Nevertheless, it seems this topic is scarcely covered in SO, so answers for other languages are ok too. although maybe those deserve a topic of its own if someone finds it relevant

Thanks.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

若言繁花未落 2024-12-09 12:46:36

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

至于锁定问题的一般解决方案......您可以查看一些提供互斥体排序的库,并检测您何时尝试锁定无序的互斥体。这种类型的解决方案正确实现可能很复杂,但是一旦到位,它就可以确保您不会进入死锁状态,因为它强制所有进程以相同的顺序获取锁(即,如果进程 A 持有锁 La,并且它尝试获取顺序正确的锁 Lb,那么它要么成功,要么锁定,但无论哪个进程持有锁 Lb 都不能尝试锁定 La,因为不满足顺序约束)。

Circular (or recursive) calls that try to acquire the same non-reentrant lock are one of the easiest to debug blocking scenarios: locking is deterministic, and can be easily checked. When the application locks, fire up the debugger and look at the stack trace to understand what locks are held and why.

As to general solutions for the problem of locking... you can look into some libraries that provide mutex ordering, and detect when you are trying to lock on a mutex out of order. This type of solutions might be complex to implement correctly, but once in place it ensures that you cannot enter a deadlock condition, as it forces all processes to obtain the locks in the same order (i.e. if process A holds lock La, and it tries to acquire lock Lb for which the ordering is correct, then it can either succeed or lock, but whichever process is holding lock Lb cannot try to lock La as the ordering constraint would not be met).

心房的律动 2024-12-09 12:46:36

如果您使用的是 Linux,则有 2 个 Valgrind 工具用于检测死锁和竞争条件: HelgrindDRD。它们是相辅相成的,值得检查它们的线程错误。

If you are on Linux there 2 Valgrind tools for detecting deadlocks and race conditions: Helgrind, DRD. They both complement each other and it's worth to check for thread errors by both of them.

清醇 2024-12-09 12:46:36

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

In linux you can use valgrind to detect deadlocks, use --tool=helgrind.

两仪 2024-12-09 12:46:36

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

如果遇到死锁,可以使用 VS2010“并行堆栈”窗口。调试->Windows->并行堆栈
该窗口将显示所有堆栈,以便您可以找到死锁的方法。

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

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

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

例子:

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];
  }
} 

Best way to detect deadlocks (IMO) is to make a test program that calls all the functions in a random order in like 30 different threads 10000s of times.

If you get a deadlock you can use VS2010 "Parallel Stacks" window. Debug->Windows->Parallel Stacks
This window will show you all the stacks, so you can find the methods that are deadlocking.

A simple strategy I use to write thread-safe objects:
A thread safe object should be safe when its public methods are called, so you don't get deadlocks when it is used.

So, the idea is to just lock all the public methods that access the object's data.
Besides that you need to insure that within the class' code you never call a public method. If you need to use one of the public methods, then make that method private, and wrap the private method with a public method that locks and then calls it.

If you want better lock granularity you could just create objects for each part that has its own lock, and lock it like I suggested. Then use encapsulation to combine those classes to the one class.

Example:

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];
  }
} 
似狗非友 2024-12-09 12:46:36

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

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

有一些死锁避免策略,涉及分配锁优先级并根据优先级对锁进行排序。不过,这些需要更改代码并执行标准。

You could find a tool that builds a call graph, and check the graph for cycles.

Otherwise, there are a number of strategies for detecting deadlocks or other circularities, but they all depend on having some sort of supporting infrastructure in place.

There are deadlock avoidance strategies, having to do with assigning lock priorities and ordering the locks according to priority. These require code changes and enforcing the standards, though.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文