分析多线程程序 [关闭]

Posted

技术标签:

【中文标题】分析多线程程序 [关闭]【英文标题】:Analyzing Multithreaded Programs [closed] 【发布时间】:2010-09-05 19:30:30 【问题描述】:

我们有一个已有数年历史的代码库,所有最初的开发人员早已不复存在。它使用了很多很多线程,但没有明显的设计或共同的架构原则。每个开发人员都有自己的多线程编程风格,因此一些线程使用队列相互通信,一些使用互斥锁锁定数据,一些使用信号量锁定,一些使用操作系统 IPC 机制进行进程内通信。没有设计文档,而且 cmets 很稀疏。这是一团糟,似乎每当我们尝试重构代码或添加新功能时,都会引入死锁或其他问题。

那么,有没有人知道任何有助于分析和记录线程之间所有交互的工具或技术? FWIW,代码库是 Linux 上的 C++,但我有兴趣了解其他环境的工具。


更新

我很欣赏迄今为止收到的回复,但我希望得到比“添加日志消息、找出发生的情况并修复它”的建议更复杂或更系统的内容。有很多工具可以用来分析和记录单线程程序中的控制流。多线程程序没有可用的东西吗?


另见Debugging multithreaded applications

【问题讨论】:

【参考方案1】:

购买一份英特尔的VTune 及其线程分析工具。它将为您提供线程行为的系统和源级别视图。它当然不会为您自动记录事情,但至少在可视化不同情况下发生的事情方面应该是一个真正的帮助。

我认为您可以下载试用版,因此值得一试。我只用过Windows版本,但是看VTune网页也有Linux版本。

【讨论】:

我试用了 VTune... 我发现我更喜欢 Apple 的 Shark 分析器,因为我发现界面和输出直观且直接。我的 2 美分。【参考方案2】:

作为一个起点,我很想在应用程序的关键点添加跟踪日志消息。这将允许你分析你的线程是如何交互的,而不会有观察线程的行为会改变它们的行为的危险(就像逐步调试的情况一样)。 我的经验是使用 .NET 平台,我最喜欢的日志记录工具是 log4net,因为它是免费的,具有广泛的配置选项,并且如果您对实现日志记录的方式很明智,那么它不会明显影响应用程序的性能。或者,在 System.Diagnostics 命名空间中有 .NET 内置的 Debug(或 Trace)类。

【讨论】:

将 Sysinternal 的免费 DebugView 程序与 System.Diagnostics.Debug/Trace 结合使用,这是从应用程序中获取调试信息的好方法,而且比 Visual Studio 的输出窗口要好得多。 我只是说:[TestFixtureSetUp] public void ConfLog4Net() log4net.Config.BasicConfigurator.Configure(new TraceAppender Layout = new PatternLayout("[%t] %m%newline"), Threshold = 级别.信息 ); 【参考方案3】:

我会首先关注共享内存锁(互斥锁和信号量),因为它们最有可能导致问题。查看哪个状态被锁保护,然后确定哪个状态受到几个锁的保护。这会让你感觉到潜在的冲突。查看持有锁的代码调用方法的情况(不要忘记虚拟方法)。尽量消除这些调用(通过减少持有锁的时间)。

鉴于持有的互斥锁列表和它们保护的状态的粗略概念,分配一个锁定顺序(即,互斥锁 A 应始终在互斥锁 B 之前使用)。尝试在代码中强制执行。

如果并发不会受到不利影响,请查看是否可以将多个锁合并为一个。例如,如果互斥锁 A 和 B 看起来可能存在死锁,并且排序方案不容易完成,则最初将它们组合成一个锁。

这并不容易,但我会以牺牲并发性为代价来简化代码以解决问题。

【讨论】:

【参考方案4】:

对于自动化工具来说,这是一个非常困难的问题。您可能想查看model checking 您的代码。不要期待神奇的结果:模型检查器在代码量和它们可以有效检查的线程数量方面非常有限。

CHESS 是一个可能对您有用的工具(尽管不幸的是它仅适用于 Windows)。 BLAST 是另一个相当强大的工具,但很难使用并且可能无法处理 C++。***还列出了StEAM,我以前没有听说过,但听起来它可能对你有用:

StEAM 是 C++ 的模型检查器。它检测死锁、分段错误、超出范围的变量和非终止循环。

或者,尝试将代码收敛到少量定义良好(最好是高级)的同步方案可能会有很大帮助。在同一个代码库中混合锁、信号量和监视器是自找麻烦。

【讨论】:

【参考方案5】:

使用 log4net 或类似工具要记住的一件事是,它们会更改应用程序的时间,并且通常会隐藏潜在的竞争条件。我们有一些写得很糟糕的代码要调试并引入了日志记录,这实际上消除了竞争条件和死锁(或大大降低了它们的频率)。

【讨论】:

【参考方案6】:

在 Java 中,您可以选择 FindBugs(用于静态字节码分析)来查找某些类型的不一致同步,也可以选择来自 Coverity、JProbe、OptimizeIt 等公司的许多动态线程分析器。

【讨论】:

【参考方案7】:

UML 不能在这里为您提供帮助吗?

如果您将代码库逆向工程为UML,那么您应该能够绘制显示类之间关系的类图。从方法是线程入口点的类开始,您可以看到哪个线程使用哪个类。根据我对Rational Rose 的经验,这可以通过拖放来实现;如果添加的类与之前的类之间没有关系,则添加的类不会被以您开始图表的方法开始的线程直接使用。这应该为您提供有关每个线程的作用的提示。

这还将显示共享的“数据对象”和特定于线程的对象。

如果您绘制一个大类图并删除所有“数据对象”,那么您应该能够将该图布局为云,每个云都是一个线程 - 或一组线程,除非代码库很糟糕。

这只会给你一个谜题的一部分,但它可能会有所帮助;我只是希望你的代码库不是太混乱或太“程序化”,在这种情况下......

【讨论】:

以上是关于分析多线程程序 [关闭]的主要内容,如果未能解决你的问题,请参考以下文章

现代 CPU 中的多线程旧遗留应用程序 [关闭]

C# 使用多线程,在关闭窗体时 怎么关闭窗体的所有线程,使程序退出

Windows IoT 上的多线程导致线程关闭

C#关闭多线程程序

单元测试多线程 程序不正常执行解决方案

分析多线程 python 应用程序