Share via


Special threads in CLR

Question: How many threads does a typical managed process have when it just starts to run?  

Answer: regardless how many threads the user creates, there are at least 3 threads for a common managed process after CLR starts up: a main thread which starts CLR and run user's Main method, CLR debugger helper thread which provides debugging service for interop debuggers like Visual Studio, and the finalizer thread which runs finalizers for unreachable objects. Depends on what the program does, CLR might create more threads to perform special tasks.   

Sometimes it is important to know what "special" threads would be created in CLR so we could understand better the implicit impact of our managed programs. Here is a list of most common special threads: 

1. Finalizer thread. The thread is to run finalizers for "dead" objects. This thread is created when GC heap is initialized during EE start up. In Rotor, the thread proc for the thread is GCHeap::FinalizerThreadStart in vm\gcee.cpp. Because GC is undeterministic and finalizers are executed in a separate thread, you can't predict when exactly an object will be finalized. Because there is only one thread to run all finalizers, if one finalizer is blocked, no other finalizers could run. So it is discouraged to take any lock in finalizer. Also see Maoni Stephens's blog for details about finalizer thread.

2. Debugger helper thread. As its name suggests, this thread helps debuggers (mixed mode and managed debugger, but not pure unmanaged debug like windbg) to get information of the managed process and to execute certain debugging operations. The thread is created when EE initializes debugger during start up. In Rotor, the thread proc for this thread is DebuggerRCThread::ThreadProcStatic (debug\ee\Rcthread.cpp) . Also see Mike Stall's blog about impact of this helper thread。

3. Concurrent GC thread (doesn't exist in Rotor). As explained in Maoni and Chris Lyon's blog, concurrent GC is a special GC mode which allows garbage to be collected while managed threads are running simultaneously. To achieve this goal, CLR creates a thread to perform GC concurrently with user threads. The thread is only created when CLR decides to do a concurrent GC (even when concurrent GC mode is on, not every GC is concurrent, read Maoni's blog for details) and will be recycled when there are no concurrent GC work to do.

4. Server GC threads (doesn't exist in Rotor). Maoni and Chris also explained Server GC mode where on multi-process machine CLR creates one GC heap for each CPU and one thread to do GC for each heap. When Server GC mode is enabled, server GC threads will be created at EE start up time when GC heaps are initialized.

5. App Domain unload helper thread. In CLR V1.X, when a thread requests to unload an App Domain and the thread is in that App Domain itself, it needs to create a worker thread to do the unloading work. The worker thread will be dead once the target AD is unloaded. In Rotor, the thread starts with UnloadThreadWorker.ThreadStart (bcl\system\Appdomain.cs) . In Whidbey, all AD unload work is performed in a special thread regardless whether the requesting thread is in the unloading domain. The helper thread is created when first non-default App Domain is created (default domain is never unloaded) and will stay alive since then. Also see Chris Brumme's blog about details of AD unload.

6. Threadpool threads. Depends on how a program use CLR threadpool, CLR might create threads of a varieties of types. There is only one thread for some thread type. For other types, number of threads is related to number of CPUs, the work load, and some user configurable settings. The thread types including wait threads (threads to perform asynchronized wait, could be more than one); worker threads (threads to execute user work item, could be more than one); Completion port threads (threads wait for completion port IO in Windows, could be more than one, doesn't exist in Rotor); Gate thread (thread help to monitor status of completion port threads and worker threads, only one); Timer thread (thread manages timer queue, only one).

Comments

  • Anonymous
    July 06, 2005
    Special threads in CLR
    CLRの実行により、どんなスレッドが実行されているかがまとめられています。このあたりは基本的知識としてとりあえず押さえておこうと思います。
    &nbsp...

  • Anonymous
    July 10, 2005

    Adam whips up some Monad script blocks to help out my poor Monad script.
    Andrew D. Birrell has...

  • Anonymous
    July 12, 2005
    Nice info! In case anybody is interested, the .net compact framework v1.0 also has 3 special threads (in addition to the UI thread):
    1. Finalizer thread
    2. Controlling various timers
    3. Tracking changes to tcp interfaces

    My only concern with all these special threads (on both platforms) is that you cannot change their thread priority. So if you radically changed the priority of your own threads, the impact on your app is not entirely under your control.

  • Anonymous
    July 19, 2005
    Note that the CLR debugger thread is used for managed-only debugging too, and not just mixed-mode. In whidbey, it always exists, even if when you're not debugging, so that it's available to service attach requests.

  • Anonymous
    August 30, 2005
    I got email asking me to explain !Threads output in details. I think this is a good question and a good...

  • Anonymous
    March 02, 2006
    That's a fair question. Part of the answer is we don't believe people could use it properly.  The...

  • Anonymous
    March 02, 2006
    I occasionaly visit Mike Stall's .NET Debugging Blog because it's interesting to peer beneath the hood...

  • Anonymous
    July 10, 2006

    There are multiple special threads which the CLR maintains and executes. Yun Jin talks about them in...

  • Anonymous
    January 11, 2007
    PingBack from http://dotnetdebug.net/2006/03/05/special-threads-in-the-clr/

  • Anonymous
    June 13, 2007
    Last update: June 13 , 2007 Document version 0.6 Preface If you have something to add, or want to take

  • Anonymous
    June 13, 2007
    INFO: · "COM Descriptor Directory" part of the PE is responsible whether executable file is

  • Anonymous
    July 29, 2007
    PingBack from http://blog.wintoolzone.com/2005/07/12/understanding-clrs-special-threads/

  • Anonymous
    November 25, 2007
    PingBack from http://feeds.maxblog.eu/item_1082405.html

  • Anonymous
    January 21, 2009
    PingBack from http://www.keyongtech.com/673541-can-lock-into-a-dispose