by luisabreu via LA.NET [EN] on 6/22/2009 7:26:37 PM
In the last post, we’ve see that multithreading is almost a necessity in GUIs. We’ve also seen that there are some gotchas associated with it: a control can only be updated from the GUI thread. In practice, this means that we’ll need to marshal back the results to the main thread when they’re ready.
In .NET, the Windows Forms introduces the ISynchronizeInvoke interface for performing that kind of operation:
public interface ISynchronizeInvoke { IAsyncResult BeginInvoke(Delegate method, object[] args); object EndInvoke(IAsyncResult result); object Invoke(Delegate method, object[] args); bool InvokeRequired { get; } }
The Control class (which is reused by all the existing controls) implements this interface, letting you marshal the results back to the main thread by calling one of the Invoke methods.
As you can see from the interface API, you can block the secondary thread until the GUI is updated (in this case, you use the Invoke method, which is equivalent to calling BeginInvoke followed by EndInvoke), or you can perform that work in asynchronous fashion, by invoking the BeginInvoke method and use one of the available approaches for waiting on the IAsyncResult returned. Besides these methods, the Control class offers two extra helper methods which you can use when you don’t need to pass parameters to the delegate:
public IAsyncResult BeginInvoke(Delegate method); public object Invoke(Delegate method);
These are just shortcuts to the previous methods and don’t offer any benefits over the interface methods.
The InvokeRequired property is there for checking if marshalling is needed. After all, you don’t want to marshal if you don’t have to, right? Checking if marshalling is needed involves getting the Win32 control’s handle and seeing its window’s thread is the same as the current one.
Internally, the control class performs several interesting steps for executing the update on GUI through the Invoke methods(sync or async):
As you’d expect, there’s a custom IAsyncResult implementation which performs many of the things we’ve seen before (like allocating a lazy event so that it is created only if it’s needed, etc, etc). To show you how easy it is to use marshalling, we’re going to create a Windows Forms test project which will use a secondary thread for calculating if a number is prime. We’ll start with a really simple form which has only one button for starting the operation:
Here’s the code we’ve added to the buttons click event:
private void button1_Click(object sender, EventArgs e) { button1.Enabled = false; ThreadPool.UnsafeQueueUserWorkItem(state => { var isPrime = CheckIfNumberIsPrime((Int32)state); Action updater = () => { MessageBox.Show(isPrime.ToString()); button1.Enabled = true; }; button1.Invoke(updater, null); }, 19// hardcoded number ); }
As you can see, we’re making sure that all UI code runs on the GUI thread. The important thing here is making sure that the Enable property is set from the correct thread. In pre-NET 2.0, you could go ahead and set a property from a secondary thread. Most of the time, things would work and you’d get occasional crashes which were difficult to debug. From .NET 2.0 onward, the behavior changed: when you’re running in a debugger, you’ll always get additional checks which verify if the code is being called from the correct thread.
As a final optimization, you’ll probably want to stop the ExecutionContext from flowing in most GUI apps (specially for full trust apps). Doing this is as simple as calling the SuppressFlow method:
ExecutionContext.SuppressFlow();
And that’s it for today. Keep tuned for more on multithreading.
Original Post: Multithreading: the ISynchronizeInvoke interface
The content of the postings is owned by the respective author. CSharpFeeds is not responsible for the contents of the postings. This site is automatically generated and cannot be reviewed for abusive content. If you find abusive content on CSharpFeeds, please contact us. Designated trademarks and brands are the property of their respective owners. All rights reserved.