Browse DevX
Sign up for e-mail newsletters from DevX


Working with .NET Threads : Page 5

This article describes the dos and don'ts of the Thread class, and presents a wrapper class that simplifies starting a thread, correctly terminates a thread, and offers a more consistent class interface than that of the raw Thread class.

Thread States
.NET manages a state machine for each thread, and moves the thread between states. The ThreadState enumeration defines the set of states a .NET managed thread can be at:

   public enum ThreadState 
      Aborted          = 0x00000100, 
      AbortRequested   = 0x00000080, 
      Background       = 0x00000004, 
      Running          = 0x00000000, 
      Stopped          = 0x00000010, 
      StopRequested    = 0x00000001, 
      Suspended        = 0x00000040, 
      SuspendRequested = 0x00000002, 
      Unstarted        = 0x00000008, 
      WaitSleepJoin    = 0x00000020 
For example, if a thread is in the middle of a Sleep(), Join(), or a wait call on one of the synchronization objects, then the thread will be in the ThreadState.WaitSleepJoin state. .NET will throw an exception of type ThreadStateException when it tries to move the thread to an inconsistent state, such as calling Start() on a thread at the ThreadState.Running state, or trying to abort a suspended thread (ThreadState.Suspended). The Thread class has a public read-only property called ThreadState you can access to find out the exact state of the thread:

   public ThreadState ThreadState { get; }
The ThreadState enum values can be bit-masked together, so testing for a given state is done typically as follows:

   Thread workerThread;
   //Some code to initialize workerThread, then:
   ThreadState state = workerThread.ThreadState;
   if((state & ThreadState.Suspended) == 
However, I don't recommend ever designing your application so that you rely on the information provided by the ThreadState property. You should design so that your code does not depend on the thread being in a particular state. In addition, by the time you retrieve the thread's state and decide to act upon it, the state may have changed. If your thread transitions between logical states (specific to your application) such as beginning or finishing tasks, use .NET synchronization objects to synchronize transitioning between those states. The only exception to this is the knowledge that the thread is alive, required sometimes for diagnostics or control flow. For that reason, the Thread class has the Boolean read-only public property IsAlive that you should use instead of the ThreadState property:

   public bool IsAlive { get; }
For example, there is little point in calling Join() on a thread if the thread is not alive:

   Thread workerThread;
   //Some code to start workerThread, then:
   Trace.WriteLine("Thread is dead");
Therefore, in general, you should avoid accessing Thread.ThreadState.

Foreground and Background Threads
.NET defines two kinds of managed threads: background threads and foreground threads. The two thread types are exactly the same except .NET will keep the process alive as long as there is at least one foreground thread running. Put differently, a background thread will not keep the .NET process alive once all foreground threads have exited.

New threads are created as foreground by default. To mark a thread as a background thread, you need to set the Thread object's IsBackground property to true:

   public bool IsBackground { get; set; }
When the last foreground thread in the application terminates, .NET shuts down the application. The .NET runtime tries to terminate all the remaining background threads by throwing ThreadAbortException in them. Background threads are a poor man's solution for application shutdown. Instead of designing the application correctly to keep track of what threads it created, which threads are still running and need to be terminated when the application shuts down, a quick and dirty solution is to let .NET try to terminate all those background threads. Normally, you should not count on .NET to kill your background threads for you. You should have a deterministic, structured way of shutting down your application, by doing your own bookkeeping and explicitly controlling the life cycle of your threads and taking steps to shut down all threads on exit.

Thanks for your registration, follow us on our social networks to keep up-to-date