Hi all,

This post is a continuation of MANAGED DEBUGGING with WINDBG. Threads. Part 1.




·         We can see all .NET related threads in our process:

There are different types of .NET threads: finalizer, GC, debugger, timer, threadpool, primary and background threads. But not all threads related to .NET are managed. We can see all .NET threads like this:

0:004> !Threads -special

ThreadCount: 2

UnstartedThread: 0

BackgroundThread: 1

PendingThread: 0

DeadThread: 0

Hosted Runtime: no

                                      PreEmptive   GC Alloc           Lock

       ID OSID ThreadOBJ    State     GC       Context       Domain   Count APT Exception

   0    1 1f3c 003ec600      6020 Enabled  0198c744:0198dfe8 003b4bd8     0 STA

   2    2  904 003f5990      b220 Enabled  00000000:00000000 003b4bd8     0 MTA (Finalizer)


       OSID     Special thread type

    1   1b08    DbgHelper

    2    904    Finalizer


·         We can inspect the .NET Thread Pool of our process:

A thread pool is a collection of worker threads that efficiently execute asynchronous callbacks on behalf of the application. The thread pool is primarily used to reduce the number of application threads and provide management of the worker threads. Applications can queue work items, associate work with waitable handles, automatically queue based on a timer, and bind with I/O.

.NET implements the entire pooling and load-balancing mechanism using the native ThreadPoolMgr class. The ThreadPoolMgr class has five main thread types, and we can only use the first two to run our managed code:

1.       Completion port thread : executes the callback function after an item is queued by QueueUserWorkItem(). If there are not enough completion port threads available, the work item is sent to the work request queue.

2.       Worker thread: services the work request queue.

3.       Gate thread: Monitors the health of the thread pool.

4.       Wait thread: to wait on a synchronization object (i.e. System.Threading.WaitHandle).

5.       Timer thread: timer callback functionality of the System.Threading.Timer class.

We can see basic information about the Thread Pool, including the number of work requests in the queue, timers and completion port threads. This info has been taken from an ASP.NET (w3wp.exe) process:

0:030> !ThreadPool

CPU utilization 4%

Worker Thread: Total: 5 Running: 5 Idle: 0 MaxLimit: 200 MinLimit: 2

Work Request in Queue: 0


Number of Timers: 8


Completion Port Thread:Total: 2 Free: 2 MaxFree: 4 CurrentLimit: 1 MaxLimit: 200 MinLimit: 2


Note that CPU utilization is the complete CPU utilization on the box, so not specifically for the ASP.NET process. In this sample, there are no work requests in the queue, and only a few timers waiting.  We have a maximum of 200 worker threads to execute our requests, and a minimum of 2 alive at any time (this comes from our machine.config settings). And currently we are executing on 5 of these. There are no work requests in the queue, so the thread pool is not exhausted. All the completion port threads are free.

·         The following list may help us identify some typical threads we may find in our applications as shown by calls to these specific functions:


-          mscorwks!DebuggerRCThread: Debugger thread.  All managed processes have a debugger thread, even if there is no debugger attached. There is only one debugger thread in a given process. This thread exists so that a managed debugger can attach and control the managed code.

-          mscorwks!GCHeap::FinalizerThreadStart: Finalizer thread. Just like the debugger thread, there is always one finalizer thread per managed process.

-          RPCRT4!LRPC_ADDRESS::ReceiveLotsaCalls: Lightweight Remote Procedure Call (RPC) thread. It’s used for local remote procedure call (LRPC) communication. Here it handles incoming RPC calls to this process.

-          aspnet_wp!wmain: Main ASP.NET thread. It has initialized the runtime, connected the named pipes back to InetInfo.exe, and created the ping thread. Once it has completed the initialization, it loops, waiting for the process to exit.

-          aspnet_wp!DoPingThread: ASP.NET ping thread. It responds to the pings it receives from the health monitoring thread in InetInfo.exe.

-          comsvcs!CSTAThreadPool::KillThreadControlLoop: COM+ thread pool.

-          comsvcs!CSTAThreadPool::LoadBalanceThreadControlLoop: COM+ thread pool.

-          ole32!CRpcThread::WorkerLoop: COM worker threads. They may be waiting for COM to dispatch work.

-          ole32!DLLHostThreadEntry: COM has created this to instantiate a COM component marked as Apartment.

-          ole32!GetToSTA: You need to switch to an STA thread in the process for components marked as Aparment. This thread switch won't happen with ASPCompat page directive or if Apartment component is in COM+ (The component must be registered in COM+ as a library application, and Synchronization must be set to Required so that it runs on a COM+ STA worker thread), which forces the page's ProcessRequest method to execute on a COM+ STA worker thread. If component is marked as Free, we can run in MTA thread.

-          comsvcs!CSTAThread::WorkerLoop: COM+ thread pool. STA threads used with ASPCompat or Aparment component in COM+. ASPCompat forces the ProcessRequest method to execute in a thread that has been initialized to the STA threading model.


Next post: MANAGED DEBUGGING with WINDBG. Thread Stacks. Part 1.

Index: MANAGED DEBUGGING with WINDBG. Introduction and Index.




Alex (Alejandro Campos Magencio)