2009-12-16 91 views
6

我有一个用C++编写的非常大的,复杂的(百万+ LOC)Windows应用程序。我们每天都会收到一些报告,说明应用程序已被锁定,并且必须强制关闭。检测应用程序挂起

虽然我们有关于崩溃的广泛报告,但我想扩大这个范围以包含这些死机情况 - 即使对于大量日志记录,我们也无法找到其中某些情况的根本原因。我们可以清楚地看到活动停止的位置 - 但不是为什么它停止,即使在评估所有线程的输出时也是如此。

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

有没有人知道更好的方式来做到这一点比这样的定期轮询主窗口?这似乎很笨拙,但我还没有看到可以在我们的平台上工作的替代方案 - Windows XP和Windows 2003 Server。我发现Vista有更好的工具,但不幸的是,这对我们无能为力。

只要说我们已经在这方面做了大量的诊断并且只得到有限的成功。请注意,实时附加windbg不是一种选择,因为我们在事件发生几小时或几天后才会收到报告。我们将能够检索内存转储和日志文件,但仅此而已。

任何超出我上面计划的建议将不胜感激。

+0

当挂起做的所有线程锁起来?该应用是否继续生成日志文件? – 2009-12-17 12:24:49

+0

您是否希望应用程序本身检测到它已挂起或正在使用单独的进程来监视应用程序? – 2009-12-17 12:26:44

+0

该应用程序在大多数情况下会继续在主窗口以外的其他线程中生成日志记录。在非常低的情况下,看起来所有的日志记录都停止在线程中。 我们希望应用程序能够自我监控。 – 2009-12-18 03:09:08

回答

2

答案很简单:SendMessageTimeout

使用这个API,您可以将消息发送到一个窗口,等待继续之前超时;如果应用程序在超时之前响应,则该程序仍在运行,否则将挂起。

+0

谢谢,我不知道这个 - 这将与我已经计划好的工作很好。 – 2009-12-18 03:07:14

1

一个建议:

假设问题是由于锁定,你可以从一个看门狗线程转储互斥&信号状态。通过一点工作(追踪你的通话图),你可以确定你是如何到达死锁的,哪些呼叫路径相互阻塞,等等。

+0

谢谢,在我们检测到我们被锁定的事实后,这是一个很好的建议 - 但我首先要找到一个可靠的方法来做到这一点。 – 2009-12-18 03:09:53

3

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

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

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

+0

谢谢,我会看看这个。我担心涉及的开销。应用程序已经很大,并且由于终端服务环境的共享特性,我们已经达到了添加任何显着的内存或CPU开销可能有问题的程度。 – 2009-12-18 03:13:35

0

虽然故障转储分析似乎识别问题提供了解决方案,在我的经验,这种情况很少,因为它缺乏的只是在飞机坠毁前发生了什么足够明确的细节结出许多果实。即使使用了你提出的工具,它也不会提供发生事件的间接证据。我敢打赌,原因是未受保护的共享数据,所以锁定轨迹不会显示它。

找到这个,在我的经验是蒸馏应用程序的逻辑,以取其精华,查明冲突必须发生的最有效的方式。有多少个线程? GUI有多少个?线程有多少点互动?是的,这是很好的旧桌子检查。主要的怀疑互动可以在一两天内确定,然后让一小群怀疑者相信互动是正确的。

+0

的确如此,我们当然也尝试过(并继续尝试),但到目前为止,我们还无法以原始形式或“修剪”形式重现此内容。即使在识别出潜在的可疑交互之后,我们仍然无法迫使这种情况发生。 我不希望转储将是灵丹妙药,但在具有堆栈跟踪可以产生大量的信息,即使没有任何转储将包含其他数据的arsenal--而另一个有力武器。 – 2009-12-18 03:11:42

+0

我不是说做可运行的蒸馏代码。我的意思是将代码提取到其功能核心和交互中,如在一张纸或白板上:'task1:initialize;循环; wait_for_signal; perform_listbox_update;直到(终止);' – wallyk 2009-12-18 03:56:17

+0

我们也从这个角度接近了。很多问题是,有几条不同的路径似乎会导致这种情况 - 所以我们并不仅仅面临一个根本原因。 – 2009-12-19 16:05:41