更新:通常该应用程序在客户位置运行,我无法访问该机器,并且不太愿意要求他们安装大量软件。
!threads
命令将显示应用程序中的所有线程,而 !clrstack
命令则会显示它们正在执行的内容。使用 ~e!clrstack
将所有线程的调用堆栈转储出来。查找调用 Wait 方法的情况,因为它们表示锁定。!syncblk
命令将给出哪些线程持有不同的锁的信息。!dso
)。从这里,你应该能够找到该线程正在尝试获取的锁。澄清:WinDbg 不需要常规安装。只需复制文件即可。另外,如果你采用了挂起转储文件,则可以在其他机器上继续调试(如果有需要)。
补充说明:Sosex 具有 !dlk
命令,可自动识别许多情况下的死锁。它并非总是有效,但当有效时,它可以为你完成所有工作,因此应该是你的首选。
除了使用常规的lock
和Monitor.Enter
锁定一些数据的方法,您还可以使用“TimedLock”结构。
如果无法及时获取锁定,此TimedLock将抛出异常,并且如果您有未释放的某些锁定,它还可以向您发出警告。
这篇文章由Ian Griffiths撰写,可能会对您有所帮助。
在并发编程中使用超时是一个可怕的想法。这会导致不确定性,因此无法重现行为。尝试使用死锁检测工具,如CHESS。更好的方法是使用无锁算法来最小化使用的锁的数量,或者完全避免使用锁,并将程序分区成单线程隔间,并使用队列在隔间之间传递数据(更常被称为消息传递/actor并发)。
http://blogs.technet.com/askperf/archive/2007/06/15/capturing-application-crash-dumps.aspx 的结尾指出,在Vista系统中,您可以使用任务管理器获取正在运行的进程的崩溃转储。
你们那里实际上有一个非常有趣的问题。有几件事情可以做:
使用好的日志记录器:复现多线程错误的一种方法是使用会打印执行操作和执行它们的线程的日志记录器,这样您就可以找到指引您找到错误的跟踪。如果您可以添加日志记录器,这是一个相当简单的解决方案。
使用FSP:使用FSP定义您的多线程系统。这样,您将能够创建一个过程的有限状态机,通过它来查找错误。这个解决方案是一个更数学化的解决方案。
我给你的两个解决方案/程序,实际上是英国大学和美国大学在处理多线程开发时的主要差异。在英国,教授们更愿意尝试使用FSP证明他们的系统没有错误,然后再进行编程,而美国人则更喜欢测试以证明它们的正确性,这是一种口味问题。
我真的建议阅读这本书:Jeff Magee和Jeff Kramer:并发:状态模型和Java程序,Wiley,1999年
这是一个非常有趣的问题,但也很痛苦,因为它只会在几天后才发生。我在CodeProject上找到了这篇文章,这可能对你有所帮助。
一种老派的方法是记录大量消息并使用日志文件来尝试检测它何时发生。 :)