【问题标题】:Debugging RtlUserThreadStart in Process Explorer在进程资源管理器中调试 RtlUserThreadStart
【发布时间】:2012-06-27 21:48:46
【问题描述】:

我有一个基于 3.5 构建的多线程 wpf 应用程序。当我通过 Process Explorer 查看正在运行的线程时,我看到 8 个线程都具有相同的起始地址 ntdll.dll!RtlUserThreadStart,并且所有 8 个线程的 CPU 值都在 3-6+ 之间,并且具有较高的 Cycles Delta。我无法弄清楚这些线程在做什么。它总是相同的线程。它永远不会在应用程序的同一实例中发生变化。当我同时调试我的应用程序并暂停调试器时,所有这些线程都为堆栈显示一行 System.Threading.ConcurrencyScheduler.Scheduler.WaitForWork() 或 System.Threading.Monitor.Wait()。

我为 Visual Studio 启用了符号文件,我在这些线程上看到了以下堆栈:

System.Threading.Monitor.Wait() Normal
mscorlib.dll!System.Threading.Monitor.Wait(object obj, int millisecondsTimeout) + 0x19     bytes
System.Threading.dll!System.Threading.ConcurrencyScheduler.Scheduler.WaitForWork() + 0xd0 bytes  
System.Threading.dll!System.Threading.ConcurrencyScheduler.InternalContext.Dispatch() + 0x74a bytes
System.Threading.dll!System.Threading.ConcurrencyScheduler.ThreadInternalContext.ThreadStartBridge(System.IntPtr dummy) + 0x9f bytes     

当我查看进程监视器中线程上提供的堆栈时,我看到以下示例:

0  ntoskrnl.exe!KeWaitForMultipleObjects+0xc0a
1  ntoskrnl.exe!KeAcquireSpinLockAtDpcLevel+0x732
2  ntoskrnl.exe!KeWaitForSingleObject+0x19f
3  ntoskrnl.exe!_misaligned_access+0xba4
4  ntoskrnl.exe!_misaligned_access+0x1821
5  ntoskrnl.exe!_misaligned_access+0x1a97
6  mscorwks.dll!InitializeFusion+0x990b
7  mscorwks.dll!DeleteShadowCache+0x31ef

或:

0  ntoskrnl.exe!KeWaitForMultipleObjects+0xc0a
1  ntoskrnl.exe!KeAcquireSpinLockAtDpcLevel+0x732
2  ntoskrnl.exe!KeWaitForSingleObject+0x19f
3  ntoskrnl.exe!_misaligned_access+0xba4
4  ntoskrnl.exe!_misaligned_access+0x1821
5  ntoskrnl.exe!KeAcquireSpinLockAtDpcLevel+0x93d
6  ntoskrnl.exe!KeWaitForMultipleObjects+0x26a
7  ntoskrnl.exe!NtWaitForSingleObject+0x41f
8  ntoskrnl.exe!NtWaitForSingleObject+0x78e
9  ntoskrnl.exe!KeSynchronizeExecution+0x3a23
10 ntdll.dll!ZwWaitForMultipleObjects+0xa
11 KERNELBASE.dll!GetCurrentProcess+0x40
12 KERNEL32.dll!WaitForMultipleObjectsEx+0xb3
13 mscorwks.dll!CreateApplicationContext+0x10499
14 mscorwks.dll!CreateApplicationContext+0xbc41
15 mscorwks.dll!StrongNameFreeBuffer+0xc54d
16 mscorwks.dll!StrongNameFreeBuffer+0x2ac48
17 mscorwks.dll!StrongNameTokenFromPublicKey+0x1a5ea
18 mscorwks.dll!CopyPDBs+0x17362
19 mscorwks.dll!CorExitProcess+0x3dc9
20 mscorwks.dll!TranslateSecurityAttributes+0x547f
21 mscorlib.ni.dll+0x8e6bc9

作为此项目的附加说明。我的电脑是一个4核的单CPU。当我们在具有 4 个内核的双 CPU 上运行相同的应用程序时,我们会看到线程数从 8 个变为 16 个。

【问题讨论】:

  • 如果您想以这种方式调试它,您将需要获得更好的调试符号。任何出现偏移量超过 0x100 的符号基本上都是垃圾,并不能告诉你到底发生了什么。现在你只能看到导出的函数。启用 Microsoft 符号服务器以获得更好的 pdb。
  • 我添加了 Visual Studio 在启用符号服务器时提供的堆栈。我不知道如何增加 Process Explorer 中提供的堆栈
  • 顺便说一句:如果进程资源管理器没有查看图像的完全权限,它似乎会显示“RtlUserThreadStart”。例如,当 MSI 安装程序运行时,我注意到了这一点。当您使用“文件 -> 显示所有进程信息”设置时,它会将堆栈解析为更深的元素。 (您还注意到,“堆栈跟踪”按钮会在没有提升权限的情况下打印错误。

标签: c# multithreading process-explorer


【解决方案1】:

可悲的是,您的问题记录不足,但合理的猜测是您似乎使用了 PPL 库。它保留了一个线程池来完成并行作业。毫无疑问,您会看到高 CPU 周期数,因为这些线程确实在执行您要求它们执行的工作。

与线程池的典型情况一样,PPL 保留这些线程以供下一项工作执行,这就是您看到它们在 WaitForWork() 上等待的原因。由于缺少调试符号,本机堆栈跟踪是垃圾。 RtlUserThreadStart 是一个 Windows 函数,你总是会在非托管堆栈跟踪中看到,这就是线程启动的方式。

这完全正常。唯一值得注意的其他信息是微软员工发布的this answer

并发运行时缓存线程以供以后重用。它们仅在所有并发运行时调度程序都已关闭时才被释放。 (通常,进程中只有一个默认调度程序)。当排队工作的所有外部线程都退出时,调度程序将关闭。因此,如果主线程安排了工作(例如通过从 main() 调用 parallel_for),那么默认调度程序将仅在进程关闭时被删除。

缓存线程数有上限。它大约是机器上内核数量的 4 倍(尽管还有一些其他因素会影响阈值,例如调度程序策略中的堆栈大小选项)。

【讨论】:

  • 我理解维护这些线程以备后用的概念。我不明白或不知道如何调试的是,为什么他们在等待工作时每个人都消耗这么多 CPU?我看到每个都消耗 3-6+% 的 cpu
  • 因为这些线程实际上在工作?您编写了一个“多线程 wpf 应用程序”,它们应该可以工作。有时,Process Explorer 不会有助于捕捉他们的工作。当它制作快照时,它正在使用你 CPU 的一个核心,这使得其中一个工作人员执行的可能性大大降低。添加检测代码或使用并发分析器以获得更好的洞察力。
【解决方案2】:

我找出了导致这些处于等待状态的线程上 CPU 使用率高的原因。我还不知道为什么会这样。当我们的应用程序是 .NET 3.5 应用程序时,这里有人发现并利用了一个可用的线程程序集,该程序集有人向后移植或来自 .NET 4.0/4.5 的东西用于 3.5。这显然在 Parallel.ForEach 调用或其他方面存在缺陷。当我调用这个调用时,我最终会在循环之后等待这些线程等待,消耗 CPU。我们与 Microsoft 确认这些线程实际上只是在等待。现在我们是 4.0,我已经切换到 4.0 可用的任务库,问题已经消失。当我有机会查看是否可以提供发生这种情况的具体原因时,我会尝试调试到库中。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-04-09
    • 2022-07-25
    • 1970-01-01
    相关资源
    最近更新 更多