C# 在 Process Explorer 中调试 RtlUserThreadStart
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/11235279/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Debugging RtlUserThreadStart in Process Explorer
提问by Ben
I have a multi-threaded wpf application built on 3.5. When I look at the running threads through Process Explorer I see 8 threads all with the same start address, ntdll.dll!RtlUserThreadStart and all eight have a CPU value from 3-6+ and have a high Cycles Delta. I can't figure out what these threads are doing. It is always the same threads. It never varies within the same instance of the application. When I debug my application at the same time and pause the debugger, all these threads are showing a single line for the stack either System.Threading.ConcurrencyScheduler.Scheduler.WaitForWork() or System.Threading.Monitor.Wait().
我有一个基于 3.5 的多线程 wpf 应用程序。当我通过 Process Explorer 查看正在运行的线程时,我看到 8 个线程都具有相同的起始地址 ntdll.dll!RtlUserThreadStart,并且所有 8 个线程的 CPU 值都在 3-6+ 之间,并且具有很高的 Cycles Delta。我无法弄清楚这些线程在做什么。它总是相同的线程。它永远不会在应用程序的同一实例中发生变化。当我同时调试我的应用程序并暂停调试器时,所有这些线程都为堆栈显示一行 System.Threading.ConcurrencyScheduler.Scheduler.WaitForWork() 或 System.Threading.Monitor.Wait()。
I enabled the symbol files for Visual Studio and I see the following stack on those threads:
我为 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
When I look at the stack provided on the thread within process monitor I see the following as examples:
当我查看进程监视器中线程上提供的堆栈时,我看到以下示例:
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
or:
或者:
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
As an additional note to this item. My computer is a single CPU with 4 cores. When we run the same app on a dual CPU with 4 cores we see this number of threads go from 8 to 16.
作为此项目的附加说明。我的电脑是一个 4 核的单 CPU。当我们在 4 核的双 CPU 上运行同一个应用程序时,我们看到线程数从 8 增加到 16。
回答by Hans Passant
Your question is woefully under-documented, but a reasonable guess is that you appear to use the PPL library. Which keeps a pool of threads around to get the parallel jobs done. You are no doubt seeing high cpu cycle counts because these threads are indeed doing the job you asked them to do.
您的问题记录不足,但合理的猜测是您似乎使用了 PPL 库。它保留了一个线程池来完成并行工作。毫无疑问,您会看到高 CPU 周期数,因为这些线程确实在执行您要求它们执行的工作。
As is typical with thread pools, the PPL keeps these threads around for the next job to do, that's why you see them waiting on WaitForWork(). The native stack traces are junk due to a lack of debugging symbols. RtlUserThreadStart is otherwise a Windows function you'll always see back in an unmanaged stack trace, that's how a thread gets started.
与线程池一样,PPL 会保留这些线程以供下一个工作完成,这就是您看到它们等待 WaitForWork() 的原因。由于缺少调试符号,本机堆栈跟踪是垃圾。RtlUserThreadStart 是一个 Windows 函数,您将始终在非托管堆栈跟踪中看到它,这就是线程启动的方式。
This is all entirely normal. The only other info worth of note is this answerposted by a Microsoft employee:
这都是完全正常的。唯一值得注意的其他信息是微软员工发布的这个答案:
The concurrency runtime caches threads for later re-use. They are released only when all the concurrency runtime schedulers have been shutdown. (Typically, there is just a single default scheduler in the process). A scheduler is shutdown when all the external threads that queued work to it has exited. So if the main thread scheduled work (by calling parallel_for from main() say) then the default scheduler would be deleted only on process shutdown.
There is an upper limit on the number of cached threads. It is rougly 4 times the number of cores on the machine (though there are some other factors affecting the threshold like the stack size option in scheduler policies).
并发运行时缓存线程供以后重用。只有当所有并发运行时调度程序都关闭时才会释放它们。(通常,进程中只有一个默认调度程序)。当所有排队工作的外部线程都退出时,调度程序将关闭。因此,如果主线程调度工作(通过从 main() 调用 parallel_for 说)那么默认调度程序将仅在进程关闭时被删除。
缓存线程的数量有上限。它大约是机器上内核数量的 4 倍(尽管还有一些其他因素会影响阈值,例如调度程序策略中的堆栈大小选项)。
回答by Ben
I figured out what is causing the high CPU utilization on these threads that are in a wait state. I don't yet know why it is happening though. When our application was a .NET 3.5 application someone here found and utilized an available threading assembly that someone had back-ported or something from .NET 4.0/4.5 for use with 3.5. This apparently has a defect in the Parallel.ForEach call or something. When I invoke this call I end up with these threads sitting around waiting, after the loop, consuming CPU. We confirmed with Microsoft that those threads were actually just waiting. Now we are 4.0 and I have switched to the task library available with 4.0 and the problem has gone away. I'll try to debug into the library when I get a chance to see if I can provide a specific reason why this was occuring.
我找出了导致这些处于等待状态的线程上 CPU 使用率高的原因。我还不知道为什么会这样。当我们的应用程序是 .NET 3.5 应用程序时,有人在这里找到并利用了一个可用的线程程序集,该程序集是有人向后移植的,或者是来自 .NET 4.0/4.5 的东西,以便与 3.5 一起使用。这显然在 Parallel.ForEach 调用中存在缺陷。当我调用这个调用时,我最终让这些线程坐在那里等待,在循环之后,消耗 CPU。我们与 Microsoft 确认这些线程实际上只是在等待。现在我们是 4.0,我已经切换到 4.0 可用的任务库,问题已经消失。当我有机会查看是否可以提供发生这种情况的具体原因时,我将尝试调试到库中。

