检测应用程序挂起

时间:2009-12-16 21:35:22

标签: c++ windows

我有一个用C ++编写的非常大,复杂(百万+ LOC)的Windows应用程序。我们每天收到一些应用程序已锁定的报告,必须强制关闭。

虽然我们有关于崩溃的广泛报告,但我想扩展它以包括这些挂起场景 - 即使有大量日志记录,我们也无法找到其中一些的根本原因。我们可以清楚地看到活动停止的位置 - 但不是为什么它停止了,即使在评估所有线程的输出时也是如此。

问题是检测何时发生挂起。到目前为止,我能想到的最好的是一个看门狗线程(因为我们有证据表明后台线程继续运行w / out问题),它定期用自定义消息对主窗口进行ping操作,并确认它是在一个自定义消息中处理的。及时时尚。这只会捕获GUI线程挂起,但这似乎是大多数情况发生的地方。如果在可配置的时间范围内未收到回复,我们将捕获内存和堆栈转储,并为用户提供继续等待或重新启动应用程序的选项。

有没有人知道比这样定期轮询主窗口更好的方法呢?它似乎非常笨拙,但我还没有看到可以在我们的平台上运行的替代方案--Windows XP和Windows 2003 Server。我看到Vista有更好的工具,但不幸的是,这对我们没有帮助。

我只想说我们对此进行了广泛的诊断,并且只取得了有限的成功。请注意,实时附加windbg不是一种选择,因为我们在事件发生后数小时或数天才收到报告。我们将能够检索内存转储和日志文件,但仅此而已。

除了我上面的计划之外,任何建议都会受到赞赏。

4 个答案:

答案 0 :(得分:3)

一种选择是始终在自己的“调试器”下运行程序。某些程序(如GetRight)执行此操作以进行复制保护,但您也可以执行此操作来检测挂起。实质上,您在程序中包含一些代码,以通过调试API附加到进程,然后使用该API定期检查挂起。当程序首次启动时,它会检查是否有一个调试器连接到它,如果没有,它会运行另一个自身的副本并附加到它 - 所以第一个实例什么也不做,只是充当调试器而第二个实例是“真实的” “一个。

如何实际检查挂起是另一个完整的问题,但是有权访问调试API,应该有一些方法可以合理有效地检查堆栈是否已经改变(即没有加载所有符号)。不过,你可能只需要每隔几分钟左右做一次,所以即使效率不高也没关系。

这是一个有点极端的解决方案,但应该是有效的。打开和关闭此行为也很容易 - 如果您愿意,可以执行命令行开关或#define。我确信那里有一些代码可以做这样的事情,所以你可能不需要从头开始。

答案 1 :(得分:3)

答案很简单: SendMessageTimeout

使用此API,您可以向窗口发送消息并等待超时,然后再继续;如果应用程序在超时之前响应,则仍然在运行,否则它将挂起。

答案 2 :(得分:1)

建议:

假设问题是由于锁定造成的,您可以转储互斥锁& amp;信号量来自监督线程。通过一些工作(跟踪您的调用图),您可以确定您是如何到达死锁,哪些呼叫路径相互阻塞等等。

答案 3 :(得分:0)

虽然故障转移分析似乎为识别问题提供了解决方案,但根据我的经验,这很少有成果,因为它缺乏关于崩溃前发生的事情的足够明确的细节。即使使用您提出的工具,它也只能提供所发生情况的间接证据。我敢打赌原因是不受保护的共享数据,因此锁定跟踪不会显示它。

根据我的经验,找到这种方法最有效的方法是将应用程序的逻辑提炼到其本质,并确定必须发生冲突的位置。有多少线程? GUI有多少?线程交互的点数是多少?是的,这是很好的旧桌子检查。可以在一两天内确定主要的可疑交互,然后只是让一小群怀疑者相信交互是正确的。