A colleague of mine at work was having some trouble with multithreading this morning and I suggested using asynchronous delegates (a delegate - something you can make do something else, in .NET this can be used as a form of trigger for starting any number of other methods that take and return the same parameters as it uses - that runs its methods in another thread). This got me thinking so I decided to do a quick tutorial for anyone else who has't yet encountered this way of doing multithreading!
This is a short sharp example, and can be created in a simple form. Remember not to try to update the form from the method being run by the delegate - if you want to do this you need to run a method that checks if InvokeRequired is true, then runs Invoke(myMethodsOwnName, new object {myFirstParameter, mySecondParameter, andSoOn}) if it is true, or does whatever UI editing is needed if false - so it is calling itself in the context of the user interface.
Anyway, on with the example!
/// <summary>
/// A button on the form
/// </summary>
private void button1_Click(object sender, System.EventArgs e)
{
delegateInstance = new ExampleDelegate(beginThink);
d.BeginInvoke(5, new AsyncCallback(finished), null);
}
This is where the program runs, a simple button that can be pressed. We want to do something CPU intensive and blocking in here but instead we create an instance of a delegate and use the BeginInvoke method, the methods parameters come first (in this case 5) and then the callback method to run, and null for the object state.
/// <summary>
/// An instance of the delegate used to call a method asynchronously
/// </summary>
private ExampleDelegate delegateInstance;
/// <summary>
/// The example delegate
/// </summary>
private delegate string ExampleDelegate(int param);
/// <summary>
/// The example method that would block the user interface
/// </summary>
/// <param name="workOn">Number of seconds to block for</param>
/// <returns>Some string</returns>
private string beginThink(int workOn)
{
Thread.Sleep(workOn*1000);
return "Done";
}
This is our ficticious CPU intensive action, in this case we'll just block the thread by seeping for workOn seconds.
/// <summary>
/// The method that is called when work is done
/// </summary>
/// <param name="results">The results of the work</param>
private void finished(IAsyncResult results)
{
MessageBox.Show(delegateInstance.EndInvoke(results));
}
And this is run when the asynchronous delegate is completed. EndInvoke automatically return the same type as the delegate, (a string) which makes this nice and easy.
Permalink