Threading in a windows form

In this chapter I will examine threading support in the .NET. To visualize and try the possibilities I will build a multithreaded Windows form. In the process of building the app we will meet some nice aspects of the C# language and the .Net FCL in general.

Introducing the thread class

The processor of your PC can only do one thing at a time and we are used to programs executing statement after statement. But actually your PC is doing several things at the same time. While you are editing your source code, your email application is collecting new messages. The processor is still executing  one instruction at a time but in the background all the different processes each get their share of processing power. This happens in such tiny time-slices that your programs seem to run continuously.

Each program is, in Windows terms, called a process. Windows takes care of all processes running getting their time slices. But inside a process it is possible to do several things at the same time as well. While you are typing a mail message the same email program is receiving new messages. These different pieces of code running inside a process (program) are called threads.

In the .net FCL there is the System.Threading namespace dedicated to threading, central is the Thread class. I will use an object of this class which will show its activity by constantly moving a trackbar on a windows form. While this trackbar is moving you can use other controls on the form to call methods on that thread object.

This is a multithreaded application, the UI thread handles the user interaction with the form and the worker thread  moves the bar. In the process of building this application I have to take some slippery side-steps. So please do not start running any code until you have read to the end.

The main UI thread

Every application has a main thread. In the code of the main form the application's threading model is set as a single apartment by applying the STAThread (Single Threaded Apartment)  attribute to the Main method.

/// <summary>
///
The main entry point for the application.
///
</summary>
[STAThread]
static void Main()

Apartments have a lot to to with (Windows) message loops and the UI in general. When you're not going to dive deep into COM you don't need to know anything about apartments. I will get back to this threading model later when I will start to care about thread safety.

The main thread is named the UIthread. It can be accessed through the static CurrentThread method of the Thread class after which its properties can be set. In the constructor of the form I will code this

Thread.CurrentThread.Name = "Main thread";
Thread.CurrentThread.Priority = ThreadPriority.Highest;

By default a thread does not have a name, setting it will make it easy to identify a thread. When more than one thread is running the threading system can give one thread priority by setting its priority property. I will give the main thread top priority as it handles the user interaction, giving that top priority will make the application responsive.

Handling exceptions

There is a lot that can go wrong when working with threads and many methods of the Thread class throw exceptions to indicate the need of intervention. I will give my app a helper method to report these exceptions on the form

private void reportException(Exception e)
{
    textBox1.Text = Thread.CurrentThread.Name + System.Environment.NewLine +
    e.GetType().Name + System.Environment.NewLine +
    e.Message;
}

The method will report the name of the thread in which the exception was thrown, the name of the exception thrown and the exception message itself. The strings are separated by the System.Newline string, which will be a CR/LF in Windows.

The worker thread

For the second, worker, thread I will create a thread object. I need some code which will run when the thread starts executing. This code is a method of the form :

private void KeepAlive()
{
    while (true)
        {
        try { trackBar1.Value+= 1;  }
        catch (Exception ex) { reportException(ex); }
        }
}

All the method does is try to move the trackbar one step further. Eventually the trackbar will reach its maximum value, to reset it I have set an eventhandler on the value-change event of the trackbar. As soon as the trackbar reaches its maximum value the eventhandler will reset the value to its minimum:

private void trackBar1_ValueChanged(object sender, System.EventArgs e)
{
    if (trackBar1.Value == trackBar1.Maximum)
        trackBar1.Value = trackBar1.Minimum;
}

To get the KeepAlive method executed in the worker thread a delegate is used. The ThreadStart delegate, found in the System.Threading namespace, has a very simple signature; it has no parameters and a void return type. The KeepAlive method has this signature.

Now I can create the thread object

t = new Thread(new ThreadStart(KeepAlive));
t.Name = "Second thread";
t.Priority = ThreadPriority.BelowNormal;

After creating the thread I will give it a name and set its priority to BelowNormal, in the competition for processing resources the main thread now has an extra advantage. The thread is ready but it's code will not execute yet.

Timers

Timers have been around for quite some time in Windows. They behave like a thread, once started they run independently somewhere in the background to fire an event once in a predefined interval. The code in this event will interrupt any other code running. I will add a timer to the form, once started the timer will report the status of the thread 1000 times a second. To do so I set the timer's interval property to 1 (millisecond), and write the following code

private void timer1_Tick(object sender, System.EventArgs e)
{
    if (ts != t.ThreadState)
    {
        listBox1.Items.Add(t.ThreadState.ToString());
        ts = t.ThreadState;
    }
}

The thread's state is kept in the private ts field, when it has really changed the new state will be reported to the listbox. The type of the ThreadState property is an bitflag enumeration of type System.Threading.ThreadState, the state of a thread is described by a combination of members. Its ToString method translates the state to a readable description of this state. After the thread is created it will read UnStarted.

Starting and pausing the thread

The code in the thread will start executing by calling the Start method of the thread object

try { t.Start(); }
catch(Exception ex) { reportException(ex); }

The result will be that the listbox will display Running and trackbar starts moving in a rapid pace. To slow down the thread and to give other threads and processes more processor resources a thread can be put to sleep for a give amount of time. I will add a checkbox and a second trackbar which the thread's code will check to see if a pause is desired and how long that pause will be: 

private void KeepAlive()
{
    while (true)
        {
            try
            {
                trackBar1.Value+= 1;
                if (checkBox1.Checked)
                    Thread.Sleep(trackBar2.Value * 100);
            }
            catch (Exception ex) { reportException(ex); }
        }
}

The Sleep method is a static method of the Thread class, it puts the current active thread to sleep. The parameter indicates the amount of time in milliseconds that the thread is supposed to sleep. It is not possible to put a thread to sleep from another thread, I cannot code t.Sleep(100), the compiler will detect this. So I have to code the Sleep statement inside the threads code.

When the checkkox is checked the trackbar will move in steps, the pace of the steps can be set with the second trackbar. The thread's state will be reported as WaitSleepJoin. There is not much to do in the thread, the chance that the timer will examine the thread while actually running is very small.

Thread safety, a first approach.

So the runtime threading system gives each thread its share of processing resources. It does so by stopping one thread and starting the next one. Without taking precautions the thread could be stopped at any point in the code. This could be quite undesirable, as it could leave the data the thread is manipulating in an unstable state. It is possible to shield of pieces of code in so called critical sections, once a critical section is started the thread cannot be stopped or interrupted until the section has finished. The easiest way to do this is using the lock statement :

private void KeepAlive()
{
    while (true)
        {
        try
            {
                lock(this)
                    {
                        trackBar1.Value+= 1;
                    }
                if (checkBox1.Checked)
                    Thread.Sleep(trackBar2.Value * 100);
            }
        catch (Exception ex) { reportException(ex); }
        }
}

The lock statement tries to insure that the update of the trackbar is always completed. The trackbar could be changed by the user with the mouse as well, one of the main reasons for locking is to prevent the corruption of data which can be accessed by several threads.

Thread safety when accessing controls

The application has two threads, the UIthread and the worker thread. The code of the worker thread consist of the KeepAlive method. The KeepAlive method accesses controls on the form. Trying to prevent conflicts the worker thread locks the control it is accessing. This approach does work for "normal" .net objects but it does not work for accessing objects with a Windows handle. Controls that can receive UI messages like mouse- or keyboard-clicks do have a Windows handle. These objects can only be directly accessed from the thread on which they were created. The controls were created in the form's constructor, that is the main UI-thread. So the code is not thread safe yet.

The methods and properties of a controls can be safely accessed using the controls Invoke method. The invoke method takes a delegate as parameter. A delegate is an object which wraps up a method of an object, they are the counterpart of method pointers in classical Windows. For a full explanation of delegates and events you are welcome to a paper on the dotnetjunkies site.

I will move all code which accesses controls to a new method :

private int FrmCallback()
{
    trackBar1.Value+= 1;
    if (checkBox1.Checked)
        return trackBar2.Value * 100;
    else
        return 0;
}

The method advances the trackbar and returns the amount of time to sleep. I also need a delegate which describes the signature of this method

delegate int MyDelegate();

With these two I can create a delegate object. The constructor of the delegate takes the method to execute as a parameter.

new MyDelegate(FrmCallback)

The implementation of the KeepAlive method changes to :

private void KeepAlive()
{
    while (true)
    {
        try
        {
            int Sleep = (int) this.Invoke( new MyDelegate(FrmCallback) );
            if (Sleep != 0)
                Thread.Sleep(Sleep);
        }
        catch (Exception ex) { reportException(ex); }
    }
}

The constructed delegate object is passed to the Invoke method of this, being the form itself. Which will result in the FrmCallBack method executing. The result of that method invocation is typecasted to an integer to get the sleep period. Now the code in the worker thread no longer accesses any objects with handles in the UI thread.

When should Invoke be used  ?

You don't have to decide yourself if you need to invoke the members of a control. The Control class has besides the Invoke method the InvokeRequired property. By reading that you can decide at run-time how if you need the Invoke method to access the control. Inside the KeepAlive method you will find out that InvokeRequired is true for all controls. Inside the FrmCallBack it is always false. The firing of the timer also accesses the listbox control, there the InvokeRequired property is false as well.

Suspending and resuming a thread

You can activate and deactivate a thread from another thread using the Suspend and the Resume methods of the Thread class. I will do this with the worker thread from buttons in the main thread.

try { t.Suspend(); }
catch(Exception ex) { reportException(ex); }

After calling the Suspend method the trackbar stops moving. The status of the thread changes twice, first it will be SuspendRequested which will very soon change to Suspended. Because the status of the thread is only checked 1000 times a second there is a good chance that you will not even see the request. The actual state displayed depends on the state it was in when calling Suspend. If it was asleep, in state WaitSleepJoin, it will now be in state WaitSleepJoin, Suspended. If it was Running it will now be a Suspended state. So you can suspend a sleeping thread and you can suspend a running thread, the fact that the state is a flags enumeration makes it possible to mark this combination of states.

Calling the Resume method will set the trackbar in motion again.

try { t.Resume(); }
catch(Exception ex) { reportException(ex); }

When resumed the thread will fall back to the state is was before Suspend was called. Suspend is a forgiving method, calling it again on a thread which is already suspended has no effect. But Resume is far more critical, calling it on a non suspended thread will throw an exception in the calling thread. That will be the main thread, not the thread object which Resume's method was called.

Interrupting and joining a thread

A thread which has been sent to sleep can be woken with the Interrupt method. 

try { t.Interrupt(); }
catch(Exception ex) { reportException(ex); }

When the thread really was asleep this will lead to an exception in the thread being interrupted. This way the thread is notified that it is woken.

If the thread was already running, nothing happens.

If one thread has to wait for another thread before it can continue, it should call the the Join method on that thread. Which will pause the calling thread and pass control to that other thread. The Join method has several overloads, the one I use here takes as a parameter the maximum amount of time the calling thread will wait.

try { t.Join(trackBar2.Value * 100); }
catch(Exception ex) { reportException(ex); }

Here I am making a call from the main UI thread. Pausing this thread will freeze the form. In the demo you can see this very clearly by setting the second trackbar to a high value, which corresponds to 8 seconds. Clicking the join button will result in a 8 second freeze of the main form.

Stopping a thread

The KeepAlive method has a loop which will run on forever. The only way to stop it is by killing the thread. This is done by calling the thread's Abort method

try { t.Abort(); }
catch(Exception ex) { reportException(ex); }

This will raise an exception in the thread which cannot be recovered from. The thread state will go from AbortRequested to Stopped. Once stopped the thread cannot be restarted, I will have to create a new thread object.

A thread which is in Suspended state cannot be successfully aborted. The calling thread will throw an exception and the thread will get stuck in an AbortRequested state. From which no successful recovery seems possible.

Stopping the application

When the form is closed the main UI thread will stop running. But this does not mean that the second worker thread will stop as well. There will no longer be any live reference to the thread object, so eventually the garbage collector will destroy the object. But until that moment the thread will stay alive in an unstable state, working with a trackbar that has gone. When you run the application from Visual Studio you will see that VS thinks the app is still running after closing its main form. If you send a break to the app VS will direct you to the KeepAlive method, that code is still running.

This means that the application has to clean up all threads before it can close. By convention the Dispose method is the place to clean up all resources used, here I can Abort the thread.

protected override void Dispose( bool disposing )
{
    if( disposing )
    {
        if ((t.ThreadState & ThreadState.Suspended) != 0)
            t.Resume();
        t.Abort();
        if (components != null)
        {
            components.Dispose();
        }
    }
    base.Dispose( disposing );
}

The Abort method will finish the thread. A suspended thread first has to be resumed before it can successfully be aborted.

Where are we ?

In this article I have examined the Thread class in .NET and its main members. Not all methods do the same thing as their name might suggest and some methods are far more critical in their usage then others. Starting a new thread is very easy, ending a thread has a couple of pitfalls. But when you know how it all works threading is powerful. In the demo application included you can try for yourself.

What's next ?

The .NET support for threading goes far beyond the material covered here. The methods provide many overloads to fine-tune their behavior. The System.Threading namespace has many more types, including support for thread-pooling and advanced thread synchronization.