有没有一种简单的方法可以通过线程转储来查找线程死锁的原因?
Is there a simple way to take a thread dump to find cause of thread deadlock?
我们在生产中有一个 C# 控制台应用程序存在间歇性线程死锁。我试图通过将 VS 2017 附加到 运行ning 进程来查找死锁,但我找不到任何方法来轻松找到死锁的原因。似乎没有任何 window 标识哪些线程拥有哪些锁。 (我尝试使用内存 window,但那根本不起作用)。
我也尝试过使用转储文件,但发现很难理解它显示的内容。 (但这是在我知道我正在寻找死锁之前。)
我习惯在 Java 中使用 JStack,它是 运行 针对 运行ning Java 应用程序的命令行实用程序,它打印线程转储,并标识死锁,并在每个 StackTrace 中显示线程锁定监视器的点。
是否有适用于 .NET 的等效工具?
当死锁发生时,我会使用 WinDbg 检查从进程中获取的完整用户转储。确保您拥有准确的二进制文件(DLL-s 和 PDB-s)以及转储文件。为您的二进制文件(32 位或 64 位)使用适当的 WinDbg 版本。
使用 File
->Open crash dump...
命令打开转储,这将在 WinDbg 中打开 "console" window。您可以通过在底部输入区域中键入命令来使用它。您可以通过在 Edit
菜单中记录来保存所有 WinDbg 输出。
您可以使用 .loadby sos clr
加载 SOS 扩展,然后使用 !EEStack
获取所有调用堆栈。您可以尝试使用 -short
参数来查看您是否在线程顶部发现了相同的函数。
正如@dmitry-egorov 在评论中所建议的,您还可以使用 SOSEX 的 !dlk
。
当您查找可能导致死锁的函数时,查找您的 函数 - 它们可能不在堆栈的最顶部但会很接近 - 一些您的函数可能会尝试以不同的顺序获取 2 个不同的锁,并且它们会死锁。
我们在生产中有一个 C# 控制台应用程序存在间歇性线程死锁。我试图通过将 VS 2017 附加到 运行ning 进程来查找死锁,但我找不到任何方法来轻松找到死锁的原因。似乎没有任何 window 标识哪些线程拥有哪些锁。 (我尝试使用内存 window,但那根本不起作用)。
我也尝试过使用转储文件,但发现很难理解它显示的内容。 (但这是在我知道我正在寻找死锁之前。)
我习惯在 Java 中使用 JStack,它是 运行 针对 运行ning Java 应用程序的命令行实用程序,它打印线程转储,并标识死锁,并在每个 StackTrace 中显示线程锁定监视器的点。
是否有适用于 .NET 的等效工具?
当死锁发生时,我会使用 WinDbg 检查从进程中获取的完整用户转储。确保您拥有准确的二进制文件(DLL-s 和 PDB-s)以及转储文件。为您的二进制文件(32 位或 64 位)使用适当的 WinDbg 版本。
使用 File
->Open crash dump...
命令打开转储,这将在 WinDbg 中打开 "console" window。您可以通过在底部输入区域中键入命令来使用它。您可以通过在 Edit
菜单中记录来保存所有 WinDbg 输出。
您可以使用 .loadby sos clr
加载 SOS 扩展,然后使用 !EEStack
获取所有调用堆栈。您可以尝试使用 -short
参数来查看您是否在线程顶部发现了相同的函数。
正如@dmitry-egorov 在评论中所建议的,您还可以使用 SOSEX 的 !dlk
。
当您查找可能导致死锁的函数时,查找您的 函数 - 它们可能不在堆栈的最顶部但会很接近 - 一些您的函数可能会尝试以不同的顺序获取 2 个不同的锁,并且它们会死锁。