Managed and Unmanaged Threading in Windows

Management of all threads is done through the Thread class, including threads created by the common language runtime and those created outside the runtime that enter the managed environment to execute code. The runtime monitors all the threads in its process that have ever executed code within the managed execution environment. It does not track any other threads. Threads can enter the managed execution environment through COM interop (because the runtime exposes managed objects as COM objects to the unmanaged world), the COM DllGetClassObject() function, and platform invoke.

When an unmanaged thread enters the runtime through, for example, a COM callable wrapper, the system checks the thread-local store of that thread to look for an internal managed Thread object. If one is found, the runtime is already aware of this thread. If it cannot find one, however, the runtime builds a new Thread object and installs it in the thread-local store of that thread.

In managed threading, Thread.GetHashCode is the stable managed thread identification. For the lifetime of your thread, it will not collide with the value from any other thread, regardless of the application domain from which you obtain this value.

Note

An operating-system ThreadId has no fixed relationship to a managed thread, because an unmanaged host can control the relationship between managed and unmanaged threads. Specifically, a sophisticated host can use the Fiber API to schedule many managed threads against the same operating system thread, or to move a managed thread among different operating system threads.

Mapping from Win32 Threading to Managed Threading

The following table maps Win32 threading elements to their approximate runtime equivalent. Note that this mapping does not represent identical functionality. For example, TerminateThread does not execute finally clauses or free up resources, and cannot be prevented. However, Thread.Abort executes all your rollback code, reclaims all the resources, and can be denied using ResetAbort. Be sure to read the documentation closely before making assumptions about functionality.

In Win32

In the common language runtime

CreateThread

Combination of Thread and ThreadStart

TerminateThread

Thread.Abort

SuspendThread

Thread.Suspend

ResumeThread

Thread.Resume

Sleep

Thread.Sleep

WaitForSingleObject on the thread handle

Thread.Join

ExitThread

No equivalent

GetCurrentThread

Thread.CurrentThread

SetThreadPriority

Thread.Priority

No equivalent

Thread.Name

No equivalent

Thread.IsBackground

Close to CoInitializeEx (OLE32.DLL)

Thread.ApartmentState

Managed Threads and COM Apartments

A managed thread can be marked to indicate that it will host a single-threaded or multithreaded apartment. The GetApartmentState, SetApartmentState, and TrySetApartmentState methods of the Thread class return and assign the apartment state of a thread. If the state has not been set, GetApartmentState returns ApartmentState.Unknown.

Note

In the .NET Framework versions 1.0 and 1.1, the ApartmentState property is used to get and set the apartment state.

The property can be set only when the thread is in the ThreadState.Unstarted state; it can be set only once for a thread.

If the apartment state is not set before the thread is started, the thread is initialized as a multithreaded apartment (MTA). The finalizer thread and all threads controlled by ThreadPool are MTA.

Important noteImportant Note:

For application startup code, the only way to control apartment state is to apply the MTAThreadAttribute or the STAThreadAttribute to the entry point procedure. In the .NET Framework versions 1.0 and 1.1, the ApartmentState property can be set as the first line of code. This is not permitted in the .NET Framework version 2.0.

Managed objects that are exposed to COM behave as if they had aggregated the free-threaded marshaler. In other words, they can be called from any COM apartment in a free-threaded manner. The only managed objects that do not exhibit this free-threaded behavior are those objects that derive from ServicedComponent.

In the managed world, there is no support for the SynchronizationAttribute unless you use contexts and context-bound managed instances. If you are using EnterpriseServices, then your object must derive from ServicedComponent (which is itself derived from ContextBoundObject).

When managed code calls out to COM objects, it always follows COM rules. In other words, it calls through COM apartment proxies and COM+ 1.0 context wrappers as dictated by OLE32.

Blocking Issues

If a thread makes an unmanaged call into the operating system that has blocked the thread in unmanaged code, the runtime will not take control of it for Thread.Interrupt or Thread.Abort. In the case of Thread.Abort, the runtime marks the thread for Abort and takes control of it when it re-enters managed code. It is preferable for you to use managed blocking rather than unmanaged blocking. WaitHandle.WaitOne,WaitHandle.WaitAny, WaitHandle.WaitAll, Monitor.Enter, Monitor.TryEnter, Thread.Join, GC.WaitForPendingFinalizers, and so on are all responsive to Thread.Interrupt and to Thread.Abort. Also, if your thread is in a single-threaded apartment, all these managed blocking operations will correctly pump messages in your apartment while your thread is blocked.

See Also

Reference

Thread.ApartmentState

Threadstate enumeration

ServicedComponent

Thread

Monitor

Change History

Date

History

Reason

December 2009

The article incorrectly stated that the apartment state is initialized to MTA if the state is set before the thread is started. The initialization to MTA occurs if the apartment state is NOT set before the thread is started.

Customer feedback.