24

可能重复:
用于查找竞争条件/死锁的 C#/.NET 分析工具

我正在调试一个我怀疑陷入僵局和挂起的应用程序。但是,这种情况每隔几天才会发生一次,而且它从未在我的计算机上发生过,因此我无法将调试器连接到它。是否有任何实用程序或方法可以用来查询正在运行的应用程序并找出哪些方法/锁/无论它是什么死锁?

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

4

7 回答 7

24

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

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

澄清:WinDbg 不需要定期安装。只需复制文件。此外,如果您使用挂起转储,如果需要,您可以在另一台机器上继续调试。

补充:Sosex!dlk在很多情况下自动识别死锁的命令。它并不总是有效,但是当它有效时,它会为您完成所有工作,因此这应该是您的首选。

于 2009-02-03T19:11:05.543 回答
9

除了使用常规的lock&Monitor.Enter方法来锁定某些数据,您还可以使用“TimedLock”结构。如果无法及时获取锁,此 TimedLock 会引发异常,如果您有一些未释放的锁,它也会给您一个警告。

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

于 2009-02-03T19:25:11.507 回答
7

并发编程中的超时是一个可怕的想法。这会导致不确定性,从而导致无法复制的行为。尝试使用像CHESS这样的死锁检测工具。更好的是,尽量减少与无锁算法一起使用的锁的数量,或者完全避免使用锁并将您的程序划分为单线程隔间,并使用队列在隔间之间传递数据(更好地称为消息传递/参与者并发)。

于 2010-03-08T19:10:30.167 回答
1

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

于 2009-02-03T18:53:38.967 回答
1

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

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

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

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

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

于 2009-02-03T19:08:35.423 回答
0

这是一个非常有趣和痛苦的问题,因为它每隔几天才会发生一次。我在 CodeProject 上找到了这篇文章。这对你来说可能是一个开始。

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

于 2009-02-03T19:01:39.650 回答
0

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

于 2009-02-03T21:42:29.983 回答