Multithreading: why multithreading on GUIs
In the latest posts, we’ve seen how to implement the event based asynchronous (EAP). When we introduced at the main features of the EAP, I’ve said that you should use this pattern when the consumers of your classes are GUIs programmers.
Since we’ve already learned lots of things about EAP, now it’s probably a good time for starting to look at asynchronous programming and GUIs. GUIs are probably one of the areas which will get the most from multithreading. To understand why, we need to make a small detour on how GUIs work in windows. Since I’m focusing on managed code, from now on I’ll be using windows forms platform for illustrating purposes (notice that the main concepts are common to unmanaged and managed code and it looks like things will remain the same for several years),
On windows, GUIs apps rely on messages for signaling several kinds of operations. What this means is that mouse, keys events, etc end up generating a message that are send to the GUI thread’s message queue. The main job of this thread is to pump the messages that are queued on the message queue.
In unmanaged code, pumping a message generally involves writing a loop that gets a message from the queue (GetMessage) and dispatches it (DispatchMessage) to a a special windows function (notice there’s always a windows function associated to a window – if you don’t create a custom one, you’ll end up with the default one). Windows functions will inspect the message and run some code in response to specific messages.
Back to the managed world and windows forms,you’ll notice that all these details are hidden by several classes. For instance,pumping messages is supported through the Application.Run call which you get by default on all the Windows Forms projects. Notice that this method “transforms” the thread on which it’s called into a GUI thread.
Windows Forms also encapsulates the so called Windows function. In fact, if you look at the Control class, you’ll see that it exposes a protected WndProc method. Internally, this method translates the windows messages into events which you might (or not) handle from your app. Notice that even though there’s plenty of stuff exposed as events, you can still overload this method if you need to handle a windows message directly.
As you can see, we can say that the final result of pumping a message is running some code that performs a specific action. In Windows Forms apps, this generally means handling an event. Now, after the previous paragraph, it should be obvious why you shouldn’t do much work from within your event handlers: if you do a lengthily operation from the GUI thread, you’re not letting it pump more messages, leading to a blocked window (something which we’ve all seen in the past – and probably cursed the guys that have written that app for it:)).
Blocking the GUI thread isn’t such a good idea either. However, it’s important to recall that in windows you can block a thread while pumping messages from the message queue. The CLR does this automatically for you and you have no control over it (which is good and bad as we’ve seen in the past).
Now, since you already know lot of things about multithreading, you know that you can easily execute that lengthily operation on a separated thread. The problem is that all windows controls have thread affinity and can only be updated from the GUI thread. This means that when we are on a secondary thread, we need to marshal the results back to the GUI thread if we need to change a property of a control.
As you can see, using separate threads on GUI programming is a must for ensuring proper response from our application. However, it also needs special care for guaranteeing that everything works as expected. In the next posts we’ll start looking at some practical examples which show how to use multithreading on GUIs and on the internal details that support this kind of operations. Keep tuned!