在调用堆栈中看到很多 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