我一直在寻找导致死锁的原因以及避免和检测它们的策略/工具。
死锁的另一个可能原因是阻塞函数以循环方式调用其他阻塞函数,因此最终调用永远不会返回。
有时这很难发现,特别是在非常大的项目中。
那么,是否有任何工具/库/技术可以自动检测程序中的循环调用?
修改 我主要使用C和C ++进行编码,因此,如果可能,请提供有关适用于这些语言的主题的任何信息。
尽管如此,似乎SO中几乎没有涵盖这个主题,所以其他语言的答案也可以。 虽然如果有人发现它相关的话,那些值得拥有的话题
感谢。
答案 0 :(得分:1)
尝试获取相同的非重入锁定的循环(或递归)调用是最容易调试的阻塞方案之一:锁定是确定性的,并且可以轻松检查。当应用程序锁定时,启动调试器并查看堆栈跟踪以了解所持有的锁和原因。
关于锁定问题的一般解决方案......您可以查看一些提供互斥排序的库,并检测何时尝试无序锁定互斥锁。这种类型的解决方案可能很难正确实现,但一旦到位它确保您不能进入死锁条件,因为它强制所有进程以相同的顺序获取锁(即,如果进程A持有锁La,并且它尝试获取订单正确的锁Lb,然后它可以成功或锁定,但无论哪个进程持有锁Lb都不能尝试锁定La,因为不会满足排序约束。)
答案 1 :(得分:1)
答案 2 :(得分:0)
答案 3 :(得分:0)
检测死锁(IMO)的最佳方法是制作一个测试程序,以随机顺序调用所有函数,如30个不同的线程10000次。
如果遇到死锁,可以使用VS2010“Parallel Stacks”窗口。调试 - > 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];
}
}
答案 4 :(得分:0)
您可以找到构建调用图的工具,并检查图表的周期。
否则,有许多策略可以检测死锁或其他循环,但它们都取决于是否有某种支持基础设施。
存在死锁避免策略,与分配锁优先级和根据优先级排序锁有关。但这些需要更改代码并执行标准。