The Invoke pattern |
Written by Mike James | ||||||
Thursday, 16 September 2010 | ||||||
Page 2 of 5
Cross threading the UIEven 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 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() 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() Now starting both threads: Thread T1=new Thread( 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.
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. <ASIN:0321636414> <ASIN:0672331012> <ASIN:0735627045> <ASIN:0470539437> <ASIN:0596159838> <ASIN:1430229799> |
||||||
Last Updated ( Monday, 20 December 2010 ) |