The System::Threading namespace contains all the classes needed to create a multithreaded application. Not only does it contain the class to create and manage a thread, but there are also classes designed to work with kernel objects, thread exceptions, and synchronization issues, such as deadlocks.
The main class within the System::Threading namespace responsible for threads is the Thread class. Within the WIN32 API, when a thread was created, you had to supply a function pointer to the function that would be used for the thread's main procedure. The Thread class's constructor within the .NET Framework is similar, but rather than using a callback function, it uses a delegate. However, even though a thread is created and is associated with a delegate, the thread does not start. In order to start a thread, you must call the Thread class method Start.
Once a thread is created, it can be placed in one of several states. The state of a thread lets you know what the thread is currently doing and can be retrieved using the ThreadState property. Once a thread is created, it is in the Unstarted state. In order to kick off the thread, which in turn calls the delegate, you call the Start method, which places the thread in the Running state. Figure 19.2 shows the flowchart for the lifetime of a thread.
Once a thread has been started, it can be placed in a state known as the WaitSleepJoin state. Although oddly named, this state is used for the different ways a state is paused. The first is if the thread itself calls one of the wait functions. A wait function allows a thread to immediately stop execution at a certain point and only return when the object it is waiting for is signaled. These objects and the method each one uses to signal other objects will be explained later in this hour. By calling the Sleep function, you can stop thread execution for a certain amount of time (expressed in milliseconds). Once the time period is finished, the thread resumes execution. The third part of the WaitSleepJoin state is based on the Join function. The Join function is not called within the context of the current thread. Instead, it is called on a separate thread variable. Calling Join suspends the calling thread until the other thread has finished executing. This is similar to calling a wait function using another thread as an object, as opposed to the other kernel objects.
After a thread is placed in the WaitSleepJoin state, there are several ways to place it into another state. If a thread is waiting for an object, the object will be placed back into the Running state when that object has been signaled. Another way to place a thread back into the Running state while it is in the WaitSleepJoin state is to interrupt it using the Interrupt method. If this method is called, the thread stops waiting for an objects signal and begins execution following the point where it began waiting. You should be careful when interrupting a thread, however. If a thread is not in the WaitSleepJoin state when the Interrupt function is called, the Interrupt function will be queued, and the next time the thread enters the WaitSleepJoin state, it will be interrupted and resume execution without waiting.
Analogous to the Interrupt function, which places a thread back into the Running state, is the Suspend function, which places a thread into a suspended or paused state. Once a Suspend request is made, the thread is placed into the SuspendRequested state. Once the thread responds to the Suspend request, it is then in the Suspended state. In order to place a thread out of the Suspended state, you can call Resume to once again place it in the Running state.
A thread can stop execution in two ways. The first way is simply for the thread to return from its procedure. Once this occurs, the thread is then in the Stopped thread state. The other way a thread can be stopped is with a call to the Abort method. Once this method is called, the thread stops execution and is placed in the Stopped state. However, a thread may not stop execution immediately. The thread will only stop execution if it is in the Running state. In other words, if a thread is waiting for a signal from another object or is suspended, it will not stop executing until it is removed from either of those states.