RSS Feed
Download our iPhone app
Browse DevX
Sign up for e-mail newsletters from DevX


Working with .NET Threads : Page 7

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.

The WorkerThread Wrapper Class
The source code accompanying this article contains the WorkerThread class, which is a high-level wrapper class around the basic .NET Thread class. WorkerThread's public methods and properties are:

   public class WorkerThread : IDisposable
      public WorkerThread();
      public WorkerThread(bool autoStart);
      public WaitHandle Handle{get;}
      public void Start();
      public void Dispose();
      public void Kill();
      public void Join();
      public bool Join(int millisecondsTimeout);
      public bool Join(TimeSpan timeout);
      public string Name{get;set;}
      public bool IsAlive{get;}
WorkerThread provides easy thread creation and other features, including a Kill() method for terminating the thread instead of using Abort(). The potentially dangerous methods of the Thread class are not present in the interface of WorkerThread, and the good ones are maintained. Listing 2 shows the implementation of WorkerThread. Because the Thread class is sealed, I had to use containment rather than derivation when defining WorkerThread. WorkerThread has the m_ThreadObj member variable of type Thread, representing the underlying wrapped thread. You can access the underlying thread via the Thread property of WorkerThread, if you still want direct thread manipulation.

Creating a New Thread
WorkerThread provides a one phase thread creation, because it can encapsulate the use of the ThreadStart delegate. Its constructor accepts a bool value called autoStart. If autoStart is true, the constructor will create a new thread and start it:

   WorkerThread workerThread;
   workerThread = new WorkerThread(true);
If autoStart is false, or when using the default constructor, you need to call the WorkerThread.Start() method, just like when using the raw Thread class:

   WorkerThread workerThread = new WorkerThread();
The thread method for WorkerThread is the private Run() method. In Listing 2, all Run() does is trace the value of a counter to the Output window. WorkerThread provides the Name property for naming the underlying thread.

Joining a Thread and the Thread Handle
WorkerThread provides a Join() method, which safely asserts that calling Join() is done on a different thread from that of the underlying thread, to avoid a deadlock. Join() also verified that the thread is not alive before calling Join() on the wrapped thread. I also wanted to expose a property of type WaitHandle, to be signaled when the thread terminates. For that, WorkerThread has a member variable of type ManualResetEvent, called m_ThreadHandle. The constructors instantiate m_ThreadHandle non-signaled. When the Run() method returns, it signals the m_ThreadHandle handle. To ensure that regardless how the Run() method exits, signaling the handle is done in a finally statement.

WorkerThread provides access to m_ThreadHandle via the Handle property. WorkerThread also provides the Boolean property, IsAlive, which not only calls the underlying thread's IsAlive property, it also asserts that the m_ThreadHandle state is consistent: you can test whether a ManualResetEvent object is signaled by waiting on it for a timeout of zero, and checking the retuned value from the Wait() method.

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