Debugging 如何证明线程池工作线程后面有IO挂起?

Debugging 如何证明线程池工作线程后面有IO挂起?,debugging,windbg,coreclr,Debugging,Windbg,Coreclr,其中一个应用程序在网络关闭后有数百个线程池线程挂起,调用堆栈位于下面 顺便说一句,在网络关闭之前,只有几十个线程,但是在网络关闭之后,线程数量在很短的时间内增加到大约400个,并且在很长一段时间内保持这个数量不变,直到我们重新启动服务器 00000020`a864fc58 00007fff`d4ea1118 ntdll!NtWaitForSingleObject+0xa 00000020`a864fc60 00007fff`ce50ce66 KERNELBASE!WaitForSingleObj

其中一个应用程序在网络关闭后有数百个线程池线程挂起,调用堆栈位于下面

顺便说一句,在网络关闭之前,只有几十个线程,但是在网络关闭之后,线程数量在很短的时间内增加到大约400个,并且在很长一段时间内保持这个数量不变,直到我们重新启动服务器

00000020`a864fc58 00007fff`d4ea1118 ntdll!NtWaitForSingleObject+0xa
00000020`a864fc60 00007fff`ce50ce66 KERNELBASE!WaitForSingleObjectEx+0x94
00000020`a864fd00 00007fff`ce50d247 clr!CLRSemaphore::Wait+0x8a
00000020`a864fdc0 00007fff`ce50d330 
clr!ThreadpoolMgr::UnfairSemaphore::Wait+0x109
00000020`a864fe00 00007fff`ce5de8b6 
clr!ThreadpoolMgr::WorkerThreadStart+0x1b9
00000020`a864fea0 00007fff`d60613d2 clr!Thread::intermediateThreadProc+0x7d
00000020`a864fee0 00007fff`d7be5454 kernel32!BaseThreadInitThunk+0x22
00000020`a864ff10 00000000`00000000 ntdll!RtlUserThreadStart+0x34

1,那么为什么在网络关闭后,线程数增加到数百个,有什么可能性

同样在我的理解中(也来自下面的源代码!WorkerseMapore->Wait…),如果调用堆栈中没有任务分配给线程,线程将被销毁\ 20秒后退出,他们只是在等待工作,没有任务分配给他们,但是这些线程从未被销毁; 在检查CoreCLR的源代码后,我注意到如果有IO挂起,即使超时20秒,线程也不会被销毁。

2,那么问题是如何通过winDBG检查用户转储来检查这些线程是否有IO挂起

顺便说一句,这些线程是在网络发生故障时创建的,并且从一开始就存在了10个多小时!失控0x4


我只需要找到一种方法来找出为什么这些线程在20秒内从未被破坏,甚至没有分配任何工作给它们,我能找出的唯一原因是这些线程后面有IO挂起,但是如何证明它?

“那么为什么在网络断开后,线程数量增加到数百个,有什么可能性?”-这个问题只与特定的、非常糟糕的设计和编写的应用程序有关。如果不深入了解此特定且未知的appabout
NtQueryInformationThread
threadisopening
,则无法回答此问题-这是从vista开始的过时版本。此调用只需检查are
ETHREAD.IrpList
is emply。但是现在Irp可以不排队到线程,而是排队到
FILE\u OBJECT
formal,如果dump中的内核地址空间可用-我们可以基于此查找
ETHREAD
对象的
IrpList
,并
NtQueryInformationThread
返回true(列表不为空)或false(列表为空)。但只有在xp/2003 io子系统中,才可以无条件地将Irp插入此列表(
IopQueueThreadIrp
)在大多数情况下从vista开始(取决于文件类型和io操作的调用方式(apc存在?iocp绑定?用户事件?)Irp可以排队到
FILE\u OBJECT
而不是-
IOPWueirptofileobject
-所以现在
threadisOpening
是不可读的方式谢谢你RbMn,所以似乎没有办法知道工作线程一直在等待的原因,比如它是由挂起的IO还是其他原因造成的?我没有研究大的源代码。我从gener说在vista之前,每个I/o操作都绑定到线程(此操作的Irp已插入到
Thread->IrpList
。但从vista开始-I/o可以绑定到文件对象,而不是线程。假设您在io调用中使用APC例程-Irp将绑定到线程,如果文件具有iocp和ApcContext!=0-Irp绑定到文件。如果io调用中使用的事件对象-depend是以同步或异步方式打开的文件理性模式。
RetryWaitForWork:
if (!WorkerSemaphore->Wait(AppX::IsAppXProcess() ? WorkerTimeoutAppX : WorkerTimeout))
{
    if (!IsIoPending())
    {      
        DangerousNonHostedSpinLockHolder tal(&ThreadAdjustmentLock);

        counts = WorkerCounter.GetCleanCounts();
        while (true)
        {
            if (counts.NumActive == counts.NumWorking)
            {
                goto RetryWaitForWork;
            }

            newCounts = counts;
            newCounts.NumActive--;

            // if we timed out while active, then Hill Climbing needs to be told that we need fewer threads
            newCounts.MaxWorking = max(MinLimitTotalWorkerThreads, min(newCounts.NumActive, newCounts.MaxWorking));

            oldCounts = WorkerCounter.CompareExchangeCounts(newCounts, counts);

            if (oldCounts == counts)
            {
                HillClimbingInstance.ForceChange(newCounts.MaxWorking, ThreadTimedOut);
                goto Exit;
            }

            counts = oldCounts;
        }
    }
    else
    {
        goto RetryWaitForWork;
    }