如何找到导致工作人员停止的 .NET 方法

Posted

技术标签:

【中文标题】如何找到导致工作人员停止的 .NET 方法【英文标题】:How to find what .NET method led caused the worker to stop 【发布时间】:2013-11-11 17:46:25 【问题描述】:

我的代码已死锁。这是主线程的堆栈跟踪:

[托管到本地转换]

WindowsBase.dll!MS.Win32.UnsafeNativeMethods.GetMessageW(ref System.Windows.Interop.MSG msg, System.Runtime.InteropServices.HandleRef hWnd,int uMsgFilterMin,int uMsgFilterMax) + 0x14 字节 WindowsBase.dll!System.Windows.Threading.Dispatcher.GetMessage(参考 System.Windows.Interop.MSG 消息,System.IntPtr hwnd,int minMessage, int maxMessage) + 0x80 字节 WindowsBase.dll!System.Windows.Threading.Dispatcher.PushFrameImpl(System.Windows.Threading.DispatcherFrame 帧)+ 0x75 字节 WindowsBase.dll!System.Windows.Threading.Dispatcher.PushFrame(System.Windows.Threading.DispatcherFrame 帧)+ 0x49 字节 WindowsBase.dll!System.Windows.Threading.Dispatcher.Run() + 0x4b 字节 PresentationFramework.dll!System.Windows.Application.RunDispatcher(对象 忽略)+ 0x17 字节 PresentationFramework.dll!System.Windows.Application.RunInternal(System.Windows.Window 窗口)+ 0x6f 字节 PresentationFramework.dll!System.Windows.Application.Run(System.Windows.Window 窗口) + 0x26 字节 PresentationFramework.dll!System.Windows.Application.Run() + 0x1b 字节 MainDashboard.exe!MainDashboard.App.Main() + 0x59 字节 C# [本地到托管转换] [托管到本地转换] mscorlib.dll!System.AppDomain.ExecuteAssembly(字符串程序集文件, System.Security.Policy.Evidence assemblySecurity, string[] args) + 0x6b 字节 Microsoft.VisualStudio.HostingProcess.Utilities.dll!Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly() + 0x27 字节 mscorlib.dll!System.Threading.ThreadHelper.ThreadStart_Context(object 状态)+ 0x6f 字节 mscorlib.dll!System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext executionContext、System.Threading.ContextCallback 回调、对象 state, bool preserveSyncCtx) + 0xa7 字节 mscorlib.dll!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext executionContext、System.Threading.ContextCallback 回调、对象 state, bool preserveSyncCtx) + 0x16 字节 mscorlib.dll!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext executionContext、System.Threading.ContextCallback 回调、对象 状态)+ 0x41 字节 mscorlib.dll!System.Threading.ThreadHelper.ThreadStart() + 0x44 bytes [本机到托管转换]

我如何知道我的代码的哪一部分负责。应用入口点是:

MainDashboard.exe!MainDashboard.App.Main() + 0x59 字节 C#

这是堆栈跟踪中唯一来自我的代码的行。

尝试查看其他两个帧的调用堆栈会显示以下内容:

当前线程当前未运行代码所有调用堆栈是 无法获取。

这里是另一个工作线程的调用栈:

[托管到本地转换]

System.dll!Microsoft.Win32.SystemEvents.WindowThreadProc() + 0xaf 字节 mscorlib.dll!System.Threading.ThreadHelper.ThreadStart_Context(对象 状态)+ 0x6f 字节 mscorlib.dll!System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext executionContext、System.Threading.ContextCallback 回调、对象 state, bool preserveSyncCtx) + 0xa7 字节 mscorlib.dll!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext executionContext、System.Threading.ContextCallback 回调、对象 state, bool preserveSyncCtx) + 0x16 字节 mscorlib.dll!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext executionContext、System.Threading.ContextCallback 回调、对象 状态)+ 0x41 字节 mscorlib.dll!System.Threading.ThreadHelper.ThreadStart() + 0x44 bytes [本机到托管转换]

这里是最后一个线程的调用栈:

[托管到本地转换]

Microsoft.VisualStudio.HostingProcess.Utilities.dll!Microsoft.VisualStudio.HostingProcess.HostProc.WaitForThreadExit() + 0x93 字节 Microsoft.VisualStudio.HostingProcess.Utilities.dll!Microsoft.VisualStudio.HostingProcess.HostProc.RunParkingWindowThread() + 0x253 字节 mscorlib.dll!System.Threading.ThreadHelper.ThreadStart_Context(对象 状态)+ 0x6f 字节 mscorlib.dll!System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext executionContext、System.Threading.ContextCallback 回调、对象 state, bool preserveSyncCtx) + 0xa7 字节 mscorlib.dll!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext executionContext、System.Threading.ContextCallback 回调、对象 state, bool preserveSyncCtx) + 0x16 字节 mscorlib.dll!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext executionContext、System.Threading.ContextCallback 回调、对象 状态)+ 0x41 字节 mscorlib.dll!System.Threading.ThreadHelper.ThreadStart() + 0x44 bytes [本机到托管转换]

应用已挂起。它总共需要处理 49,000 条记录。它停在3,029。该应用程序此时未使用任何资源。任务管理器显示它使用 0% CPU。 UI 是响应式的,但它的设计始终是响应式的。

此外,这不是确定性的。我的意思是,如果我重新启动应用程序,它会在代码中的不同位置挂起,因此没有一条记录存在导致整个事情崩溃的问题。

【问题讨论】:

堆栈跟踪如何查找其他线程? 某些版本的 Visual Studio 有一个并发可视化工具,应该可以做你想做的事。 @kkokosa,我用其他调用堆栈编辑了这个问题。 处理已停止的事实并不意味着存在任何死锁。这可能与您的主处理循环不正确地获取break 一样简单,或者引发了一些异常并且一些外部try/catch 已跳出您的主处理循环并因此停止了该过程。如果您连接了调试器,请检查输出是否有任何first-chance exception 通知。任何 NullReference、ArgumentOutOfRange、NotImplemented、InvalidOperation 等都可能是错误处理错误的标志,只会停止循环。 try ... catch 放入您的线程并让他们记录异常情况如何? 【参考方案1】:

由于您现在在“输出”中注意到“第一次机会异常”并且它们似乎会杀死您的线程,因此除了 try/catch/log 之外,还有一件事。

进一步使用 VS/CLR 的调试功能。转到 DEBUG 菜单,然后找到 EXCEPTIONS 然后找到一个(或全部,但我更喜欢一个接一个)您识别为抛出并杀死您的线程的异常,即 InvalidOperationException 并检查勾选“throw " 或 "未处理" (取决于您想要什么以及您拥有的 VS 版本)。

现在,假设您勾选了“抛出”,IDE 将自动中断/停止程序,只要它试图抛出这种类型的异常。

..它不仅会停止程序,还会像你放置断点一样跳转到那里。您将立即获得您想要检查的所有堆栈跟踪、变量、代码等。

但是,另一方面,如果您的应用程序正在以每秒数千的速率发送这种异常的垃圾邮件,只是因为有人懒惰并且 if/else 遇到了一些错误的参数情况,而是尝试/捕获了异常,然后试图依靠这个被“抛出”的异常将..好吧..失败。在这种情况下,您可能想尝试使用“未处理”的勾号(如果您在 IDE 中看到它),但当然它也有其自身的局限性。尽管如此,如果您可以将 IDE 附加到失败的进程,它们确实是非常宝贵的工具。 Insta-break 在有问题的未知线路上!

【讨论】:

【参考方案2】:

听起来您在识别应用中发生的事情时遇到了麻烦,而且您没有日志记录......

http://logging.apache.org/log4net/

在尝试解决这类问题时,日志文件非常宝贵。

实现 Log4net,将其配置为写入日志文件并开始记录内容...

例如在方法开始时您怀疑可能涉及的地方

private void MethodName()

    logger.Debug("Begin MethodName");

以及方法的结束

    logger.Debug("End MethodName");

很快你就会得到你需要的线索。

您可以自定义实际记录的内容,以便获得详细的调试记录或仅记录错误。

如果您还没有使用 Visual Studio 的“调试位置”工具栏,请使用它。

【讨论】:

log4net 不是控制台输出更好的解决方案。持久日志记录的优势在于已部署的系统 - 没有附加调试器。这根本不是答案。 在这种情况下使用调试器是没有用的,在多线程应用程序中设置断点会改变时间,从而改变应用程序的行为。因此,正如您自己在无法附加调试器的情况下所说的那样,日志记录是他的最佳选择 Log4net 将自动为您记录线程号,以便您确定哪个线程负责记录。 Console.Write 不这样做。 Log4net 允许您以多种方式输出日志,并且以最少干扰且不太可能干扰程序正常运行的方式进行。 Console.Write 不这样做。 Log4net 可以通过配置打开和关闭,Console.Write 不这样做

以上是关于如何找到导致工作人员停止的 .NET 方法的主要内容,如果未能解决你的问题,请参考以下文章

如何找到 ASP.Net 网站中的死锁

cdr显示出现一个问题,导致程序停止工作,怎么解决

为什么TwinCAT3老是已停止工作

NodeJS Broken Pipe 导致我的 Express api 停止工作

如何解决win7系统之家资源管理器已停止工作

c#获取活动窗口文本(导致vshost32.exe停止工作)