在过去的几个月中,我几乎没有收到QA关于我们的一项服务挂起的报告。在使用WinDbg检查挂起转储时,每次我发现相同的情况:加载程序锁关键部分是锁定的,但是没有找到拥有线程。由于线程已经消失,而且我能看到的唯一跟踪是它留下的全局关键部分,所以我看不到线程上运行的代码,甚至看不到线程来自什么DLL,它甚至可能不是我们的(即第三方供应商)。
这个问题是非常零星的,在过去的6个月里,它在野外自然发生了3到4次。所有其他时间,服务运行完美。所以这让我相信这是某种时间/比赛条件的问题。
最近,我决定自己解决这个问题。我使用WinTask脚本设置了一台机器,该脚本不断地启动/停止上述服务。好消息是,在5-6小时内,我可以重现这个问题。
接下来的部分:我如何隔离它?
这就是我迄今为止尝试过的:
我写这篇文章是为了万一你们能想到一些我没有考虑的事情。
我认为有一个windows实用程序人为地在CPU上加载,并做了其他事情来使竞赛条件弹出,我认为应用程序验证器做了这样的事情,但显然它没有。有人知道我在做什么吗,还是我只是梦想着呢?
除非周末发生了什么事情,否则我的下一步将是禁用所有调试器,返回股票并黑掉DllMains中的一个来记录线程_ back /线程_DETACH事件。至少在创建线程时,我能够拦截即将死亡的线程。这可能会给我们一些启示。
发布于 2012-01-15 16:05:39
我可能会尝试附加一个内核调试器,然后在Appilcation下运行这个进程。AV有卸载DLL的检查,同时保存CS和仍然持有CS的终止线程。因此,这些断点应该在内核调试器中触发,然后希望您能够在操作中捕捉到它。在KD下运行它,希望不会像用户模式调试器那样减慢速度。
发布于 2012-01-17 02:43:43
结果我比我意识到的更接近解决方案。由于在cdb下运行的服务更改了时间,然后使用应用程序验证器运行它,而应用程序验证器对时间进行了更多的更改(启用了页面堆使分配速度更慢),所以我丢失的秘密成分是prime95.exe。运行prime95.exe时超出正常优先级,无论我试图不改变什么时间,都会搞砸,但它使问题在15分钟内出现。
原因:
第三方SDK用于从硬件板获取数据。当我们的服务启动时,我们会查询不同的捕获组件的功能。查询完成后,我们释放组件实例。显然,这个DLL启动了一个单独的线程,该线程获得了一个加载程序锁,然后在该线程中进行了大量初始化。如果在此期间完成了我们的功能查询并发布了组件,那么他们的代码将在这个线程上调用TerminateThread(),从而使加载程序锁永久锁定。Prime95减慢了所有的速度,足以让我捕捉到这个竞赛条件,并获得以下验证器停止消息:
=======================================
VERIFIER STOP 00000200: pid 0x1A8C: Thread cannot own a critical section.
0000091C : Thread ID.
77E17340 : Critical section address.
00000000 : Critical section debug information address.
00000000 : Critical section initialization stack trace.有趣的是,这个线程毫无例外地正在“消失”,所以调试器甚至不会抓住任何机会。谁使用TerminateThread?
谢谢大家的建议和支持。实际上,我开始期待着在午餐的时候开车去无线电棚买一条串行电缆,然后花几天时间和KD玩。看来那得等到下一次了:)
发布于 2012-01-15 17:13:26
一些随机的想法:如果附加调试器没有帮助,那么插装(最后一点)是下一步。但是,一个线程如何在不中断整个进程的情况下就死掉了,您是否在某个地方捕获异常呢?你可能也想在那里伐木。如果这有帮助的话,您也可以将WinDbg设置为打破所有初次机会异常。即使没有中断,WinDbg输出窗口也会显示首次出现的异常。
https://stackoverflow.com/questions/8867904
复制相似问题