The Invoke pattern
Written by Mike James   
Thursday, 16 September 2010
Article Index
The Invoke pattern
Cross threading
Invoke
Asychronous calls
ISynchronizeInvoke Interface

Banner

Cross threading the UI

Even though the above example is very simple it already contains some interesting problems.

The first is the use of the messagebox to display the result.

Threads often have to interact with the UI and this presents some challenges. The WPF/Silverlight classes work  differently with respect to threads compared to the original Windows Forms classes and explaining how WPF deals with threads would require another article so for the sake of simplicity let’s concentrate on how threads interact with a Windows Forms UI - what happens with WPF is very similar but there are some differences in the way they are dispatched.

You might wonder why you can’t just drop a multi-line textbox on the form and use that to display the progress of the thread in a much neater way.

If you try to make this modification you will discover that a “cross threading” error message appears. In an attempt to protect you from some of the dangers of multi-threading .NET introduced a test to make sure that only the thread that created UI components is allowed to work with them. You can switch this test off but it isn’t a good idea.

However as an example of what can go wrong let’s do just that…

To turn off cross thread checking simply set the static CheckForIllegalCrossThreadCalls variable to false:

Control.CheckForIllegalCrossThreadCalls 
=false;

Now you can write to any control on the form without any cross threaded errors which you can demonstrate by changing the method to:

public void CountUp()
{
for (int i = 0; i < 99; i++)
this.textBox1.Text += i.ToString() +
Environment.NewLine;
}

Now the list of numbers appears in the textbox with no errors. If you can cross thread the UI in this way with no real problems why not do it?

To see that this isn’t quite as safe as it appears we need another thread:

public void CountDown()
{
for (int i = 999; i >0; i--)
this.textBox1.Text +=i.ToString() +
Environment.NewLine;
}

Now starting both threads:

Thread  T1=new Thread(
new ThreadStart(CountUp));
T1.Start();
Thread T2 = new Thread(
new ThreadStart(CountDown));
T2.Start();

Now you can see both threads getting turns to run and fill the textbox with data.

However if you look carefully you will notice that there every now and again a few values go missing after the changeover and, worse, occasionally you will see a strange character appear in the textbox – see Figure 1.

 

cross

Figure 1:

Strange things happen when two threads share a control

 

The reason for this is that none of the controls are “threadsafe”.

Consider what happens if thread 1 is in the middle of printing 65 and thread 2 takes over in mid-process.

The Textbox control will be in a half-used state and thread 2 will start to use it as if it was initialised in some way.

The result of using a such a control is unpredictable. A threadsafe control would have to reset its entire state when any of its methods were entered and this clearly isn’t useful. As a result no attempt has been made to make controls threadsafe and hence there is the need to restrict access to them to the UI thread that created them.

Things like this go wrong whenever threads share resources and it’s the big problem we have to solve.

At this point most accounts of threading start to explain how to synchronise threads using locks of one sort or another. This is an important topic but before examining how locks work let’s take a look at the alternative .NET provides specifically for accessing the UI from another thread - Invoke.

Banner

<ASIN:0321636414>

<ASIN:0672331012>

<ASIN:0735627045>

<ASIN:0470539437>

<ASIN:0596159838>

<ASIN:1430229799>



Last Updated ( Monday, 20 December 2010 )