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();
workerThread.Start();
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.