Thread States
The last few topics in this article are really just the few bits of reference information I dug up on dotNet threads. This section describes the states of a thread. The Thread object in the dotNet framework has a property called the ThreadState, which is one of the members of the following enumeration, which I pulled from the dotNET documentation.
public enum ThreadState
{
Running = 0,
SuspendRequested = 2,
Background = 4,
Unstarted = 8,
WaitSleepJoin = 32,
Suspended = 64,
AbortRequested = 128,
Aborted = 256
};
Unfortunately, I have been able to generate ThreadState’s that are not in this enumeration. Specifically, the Stopped ThreadState seems to be missing and is easy to generate. If you check the state of a thread that has run to completion, then the state is marked as Stopped.
What I also found is that it is quite easy to generate dual states. You can be in the AbortRequested state and the WaitSleepJoin state. If you catch the ThreadAbortException and then call Thread.Sleep, then the ThreadState will be “WaitSleepJoin, AbortRequested”, a dual state. The same is true if you are sleeping when the Suspend instance method is called.
Figure 1: State Diagram
Immediately after the call to the Suspend instance method, the ThreadState property reports “SuspendRequested, WaitSleepJoin”, then quickly changes to “WaitSleepJoin, Suspended”. I’ve encountered a few state diagrams that tried to depict the state transitions of dotNet threads. I must say that most are misleading or incomplete.
The biggest problem is that most of the state diagrams did not attempt to account for dual states. My own attempt at the state diagram, I know, is still lacking but much further along then anything else I’ve seen (see Figure 1).
Background Threads
There is still a lot missing from the state diagram. Specifically, what happens when you Suspend(), Wait(), Join(), Sleep(), Abort() a background thread. I’m not going to confuse the diagram to explain these new states. Rather, let me explain that a thread is either a background thread or a foreground thread. Actions on a background thread are equivalent to actions on a foreground thread, except in one respect, which I will explain in the next paragraph.
So, if you attempt to suspend a running background thread, then it will move to the SuspendRequested state, then to the Suspended state and finally back to the Background state, in the same manner as a foreground thread.
The difference between a background thread and a foreground thread is pretty simple. When the last foreground thread of a process is stopped, then the process terminates. There could be zero, 1 or an infinite number of background threads and they have no vote in whether a process terminates or not. So when the last foreground thread stops, then all background threads are also stopped and the process is stopped.
I’ve seen quite a few dot-NET programmers incorrectly use the background thread to mean any thread created using the Thread constructor. The terminology is therefore getting very confusing. The correct meaning of background thread in dotNet framework is a thread that does not have impact on whether a process is terminated.
Thread Safe Objects and Types
Here’s a rather interesting tidbit of news. Many of the dotNet objects and types are thread-safe. The first time I heard that I was rather confused at what it could mean. Does this mean an increment (++) operation on a C# integer is atomic?
I put together a small piece of C# code that launched a thousand threads and incremented and decremented one integer a million times per thread. I structured the code to swap the threads like mad to try and create a race condition that would invalidate the operations on the integer.
I was unsuccessful in generating incorrect results. So, I assume the operation is atomic. But I don’t have any proof (beyond proof-by-example) that it is an atomic operation.
Interlocked
Throughout this article, I have written code that assumes that some operations on C# objects and types are atomic. I would never suggest writing such code in a production environment. In such an environment, you will have to fall back onto our old InterlockedIncrement and InterlockedDecrement friends. In C#, these are in the System.Threading.Interlocked class. The class has two static methods Interlocked.Increment and Interlocked.Decrement. Use them well.
Page 6: Conclusion
I started this trek into dotNet threads for one reason. I wanted to evaluate them as a possible alternative for servers that require a lot of thread programming.
What I found was that dotNet’s Threading namespace is by far the easiest way to write applications that require a lot of thread programming. I didn’t find any performance problems with the dotNet threads, but neither did I find them any faster than other thread libraries available in C++ or Java threads.
For more great programming articles, please visit http://www.devarticles.com. If you have an opinion or question about this article, then please post it at the devArticles developer forum, which is located at http://www.devarticles.com/forum