检测C#应用程序中的死锁

时间:2009-02-03 18:47:58

标签: c# multithreading deadlock

  

可能重复:
  C#/.NET analysis tool to find race conditions/deadlocks

我正在调试一个我怀疑正在陷入僵局并挂起的应用程序。但是,这只会每隔几天发生一次,并且它永远不会发生在我的计算机上,因此我无法将调试器挂钩。是否有任何实用程序或方法可以用来查询正在运行的应用程序,并找出哪些方法/锁定/它是什么死锁?

更新:通常情况下,应用程序在客户位置运行,我无权访问该计算机,而且我不太愿意让他们安装大量软件。

7 个答案:

答案 0 :(得分:23)

您可以使用WinDbg检查应用程序中的线程。以下是您可以做的简要计划。

  • 当应用程序挂起时,将WinDbg文件复制到计算机上。
  • 将WinDbg附加到进程或使用ADPlus获取进程的挂起转储。如果选择ADPlus,则在WinDbg中加载转储。
  • 从WinDbg加载sos.dll,以便检查托管代码。
  • !threads命令将显示应用程序中的所有线程,!clrstack命令将显示它们正在执行的操作。使用~e!clrstack转储所有线程的调用堆栈。查找Wait方法的调用,因为它们表示锁定。
  • !syncblk命令将为您提供有关哪些线程持有不同锁的信息。
  • 要找出给定线程尝试获取的锁定,请切换到该线程并检查堆栈对象(!dso)。从这里你应该能够找到线程试图获取的锁。

澄清:WinDbg不需要定期安装。只需复制文件。此外,如果您执行挂起转储,则可以根据需要继续在另一台计算机上进行调试。

添加:Sosex具有!dlk命令,可在许多情况下自动识别死锁。它不会一直有效,但是当它发生时,它会为你完成所有的工作,所以这应该是你的第一选择。

答案 1 :(得分:8)

而不是使用常规lock& Monitor.Enter锁定某些数据的方法,您也可以使用'TimedLock'结构。 如果无法及时获取锁,则此TimedLock会抛出异常,如果您有一些未释放的锁,它也会发出警告。

Ian Griffiths的文章可能有所帮助。

答案 2 :(得分:6)

并发编程的超时是一个可怕的想法。这导致非确定性,从而导致无法再现的行为。尝试使用像CHESS这样的死锁检测工具。更好的是,最小化无锁算法使用的锁的数量,或完全避开锁并将程序划分为单线程隔离区并使用队列在隔离专区之间传递数据(更好地称为消息传递/ actor并发)。

答案 3 :(得分:1)

http://blogs.technet.com/askperf/archive/2007/06/15/capturing-application-crash-dumps.aspx的结尾说在Vista上至少可以使用任务管理器获取正在运行的进程的崩溃转储。

答案 4 :(得分:1)

你实际上有一个非常有趣的问题。你可以做几件事:

使用一个好的记录器:重现多线程错误的一种方法是使用一个记录器来打印所采取的动作和执行它们的线程,这样你就可以找到跟踪你的错误指南。如果您可以添加记录器,这是一个相当简单的解决方案。

使用FSP:使用FSP定义多线程系统。这样,您就可以创建流程的有限状态机,您可以通过它来查找错误。该解决方案是更加数学的解决方案。

我给你的两个解决方案/程序正是一些英国大学和Amercian之间接近多线程发展的主要区别。在英国,教授们更善于尝试并证明他们的系统在编程之前没有使用FSP的错误,并且美国人更喜欢测试证明他们正常工作,这是一个品味问题。

我真的建议你阅读这本书:Jeff Magee和Jeff Kramer:并发:状态模型和Java程序,Wiley,1999

答案 5 :(得分:0)

这是一个非常有趣的问题和痛苦,因为它每隔几天就会发生一次。我找到了this article on CodeProject。这可能是一个开始。

旧学校的方法是记录大量消息并使用日志文件来尝试检测它何时发生。 :)

答案 6 :(得分:0)

除了这里的答案之外,您通常会发现线程编程有用的另一件事是确保您的开发框是多处理器机器,特别是死锁(通常)更可靠地再现。