在调用堆栈中看到很多 clr!CLR Semaphore::Wait
See lots of clr!CLRSemaphore::Wait in call stack
我们看到很多如下所示的调用堆栈,我可以知道发生这种情况的条件是什么吗?
OS Thread Id: 0x48654 (559)
Current frame: ntdll!NtWaitForSingleObject+0xa
Child-SP RetAddr Caller, Callee
00000020a76cf480 00007fffd4ea1118 KERNELBASE!WaitForSingleObjectEx+0x94, calling ntdll!NtWaitForSingleObject
00000020a76cf520 00007fffce50ce66 clr!CLRSemaphore::Wait+0x8a, calling kernel32!WaitForSingleObjectEx
00000020a76cf5e0 00007fffce50d247 clr!ThreadpoolMgr::UnfairSemaphore::Wait+0x109, calling clr!CLRSemaphore::Wait
00000020a76cf620 00007fffce50d330 clr!ThreadpoolMgr::WorkerThreadStart+0x1b9, calling clr!ThreadpoolMgr::UnfairSemaphore::Wait
00000020a76cf6c0 00007fffce5de8b6 clr!Thread::intermediateThreadProc+0x7d
00000020a76cfb40 00007fffce5de89f clr!Thread::intermediateThreadProc+0x66, calling clr!_chkstk
00000020a76cfb80 00007fffd60613d2 kernel32!BaseThreadInitThunk+0x22
00000020a76cfbb0 00007fffd7be5454 ntdll!RtlUserThreadStart+0x34
OS Thread Id: 0x3bd4c (560)
Current frame: ntdll!NtWaitForSingleObject+0xa
Child-SP RetAddr Caller, Callee
00000020a774e910 00007fffd4ea1118 KERNELBASE!WaitForSingleObjectEx+0x94, calling ntdll!NtWaitForSingleObject
00000020a774e9b0 00007fffce50ce66 clr!CLRSemaphore::Wait+0x8a, calling kernel32!WaitForSingleObjectEx
00000020a774ea70 00007fffce50d247 clr!ThreadpoolMgr::UnfairSemaphore::Wait+0x109, calling clr!CLRSemaphore::Wait
00000020a774eab0 00007fffce50d330 clr!ThreadpoolMgr::WorkerThreadStart+0x1b9, calling clr!ThreadpoolMgr::UnfairSemaphore::Wait
00000020a774eb50 00007fffce5de8b6 clr!Thread::intermediateThreadProc+0x7d
00000020a774ec30 00007fffd7c00c75 ntdll!RtlpLowFragHeapAllocFromContext+0x355, calling ntdll!memset
正如 @Harry Johnston 已经在评论中提到的,这些是线程池的工作线程,它们无关紧要。
以下示例可用于复制此类堆栈。它将创建 12 个线程池工作线程,当调试器中断时,如您所见,它们都处于空闲状态。
代码基于微软的Fibunacci threadpool example:
using System.Diagnostics;
using System.Threading;
public class Fibonacci
{
public void ThreadPoolCallback(object threadContext)
{
FibOfN = Calculate(N);
DoneEvent.Set();
}
public int Calculate(int n)
{
if (n <= 1) return n;
return Calculate(n - 1) + Calculate(n - 2);
}
public int N { get; set; }
public int FibOfN { get; private set; }
public ManualResetEvent DoneEvent { get; set; }
}
public class ClrSemaphoreWaitDemo
{
static void Main()
{
const int numberOfTasks = 12;
var doneEvents = new ManualResetEvent[numberOfTasks];
var fibArray = new Fibonacci[numberOfTasks];
ThreadPool.SetMaxThreads(numberOfTasks, numberOfTasks);
ThreadPool.SetMinThreads(numberOfTasks, numberOfTasks);
for (int i = 0; i < numberOfTasks; i++)
{
doneEvents[i] = new ManualResetEvent(false);
fibArray[i] = new Fibonacci {N= 4, DoneEvent= doneEvents[i]};
ThreadPool.QueueUserWorkItem(fibArray[i].ThreadPoolCallback, i);
}
WaitHandle.WaitAll(doneEvents);
Debug.WriteLine("Now run .symfix; .reload; .loadby sos clr; !threads; !threads; !findstack clr!CLRSemaphore::Wait");
Debugger.Break();
}
}
当调试器中断时,运行以下命令:
.symfix; .reload; .loadby sos clr; !threads; !threads; !findstack clr!CLRSemaphore::Wait
我们看到很多如下所示的调用堆栈,我可以知道发生这种情况的条件是什么吗?
OS Thread Id: 0x48654 (559)
Current frame: ntdll!NtWaitForSingleObject+0xa
Child-SP RetAddr Caller, Callee
00000020a76cf480 00007fffd4ea1118 KERNELBASE!WaitForSingleObjectEx+0x94, calling ntdll!NtWaitForSingleObject
00000020a76cf520 00007fffce50ce66 clr!CLRSemaphore::Wait+0x8a, calling kernel32!WaitForSingleObjectEx
00000020a76cf5e0 00007fffce50d247 clr!ThreadpoolMgr::UnfairSemaphore::Wait+0x109, calling clr!CLRSemaphore::Wait
00000020a76cf620 00007fffce50d330 clr!ThreadpoolMgr::WorkerThreadStart+0x1b9, calling clr!ThreadpoolMgr::UnfairSemaphore::Wait
00000020a76cf6c0 00007fffce5de8b6 clr!Thread::intermediateThreadProc+0x7d
00000020a76cfb40 00007fffce5de89f clr!Thread::intermediateThreadProc+0x66, calling clr!_chkstk
00000020a76cfb80 00007fffd60613d2 kernel32!BaseThreadInitThunk+0x22
00000020a76cfbb0 00007fffd7be5454 ntdll!RtlUserThreadStart+0x34
OS Thread Id: 0x3bd4c (560)
Current frame: ntdll!NtWaitForSingleObject+0xa
Child-SP RetAddr Caller, Callee
00000020a774e910 00007fffd4ea1118 KERNELBASE!WaitForSingleObjectEx+0x94, calling ntdll!NtWaitForSingleObject
00000020a774e9b0 00007fffce50ce66 clr!CLRSemaphore::Wait+0x8a, calling kernel32!WaitForSingleObjectEx
00000020a774ea70 00007fffce50d247 clr!ThreadpoolMgr::UnfairSemaphore::Wait+0x109, calling clr!CLRSemaphore::Wait
00000020a774eab0 00007fffce50d330 clr!ThreadpoolMgr::WorkerThreadStart+0x1b9, calling clr!ThreadpoolMgr::UnfairSemaphore::Wait
00000020a774eb50 00007fffce5de8b6 clr!Thread::intermediateThreadProc+0x7d
00000020a774ec30 00007fffd7c00c75 ntdll!RtlpLowFragHeapAllocFromContext+0x355, calling ntdll!memset
正如 @Harry Johnston 已经在评论中提到的,这些是线程池的工作线程,它们无关紧要。
以下示例可用于复制此类堆栈。它将创建 12 个线程池工作线程,当调试器中断时,如您所见,它们都处于空闲状态。
代码基于微软的Fibunacci threadpool example:
using System.Diagnostics;
using System.Threading;
public class Fibonacci
{
public void ThreadPoolCallback(object threadContext)
{
FibOfN = Calculate(N);
DoneEvent.Set();
}
public int Calculate(int n)
{
if (n <= 1) return n;
return Calculate(n - 1) + Calculate(n - 2);
}
public int N { get; set; }
public int FibOfN { get; private set; }
public ManualResetEvent DoneEvent { get; set; }
}
public class ClrSemaphoreWaitDemo
{
static void Main()
{
const int numberOfTasks = 12;
var doneEvents = new ManualResetEvent[numberOfTasks];
var fibArray = new Fibonacci[numberOfTasks];
ThreadPool.SetMaxThreads(numberOfTasks, numberOfTasks);
ThreadPool.SetMinThreads(numberOfTasks, numberOfTasks);
for (int i = 0; i < numberOfTasks; i++)
{
doneEvents[i] = new ManualResetEvent(false);
fibArray[i] = new Fibonacci {N= 4, DoneEvent= doneEvents[i]};
ThreadPool.QueueUserWorkItem(fibArray[i].ThreadPoolCallback, i);
}
WaitHandle.WaitAll(doneEvents);
Debug.WriteLine("Now run .symfix; .reload; .loadby sos clr; !threads; !threads; !findstack clr!CLRSemaphore::Wait");
Debugger.Break();
}
}
当调试器中断时,运行以下命令:
.symfix; .reload; .loadby sos clr; !threads; !threads; !findstack clr!CLRSemaphore::Wait