Introduction
ThreadPool.QueueUserWorkItem
does not provide an easy way to pass more than one typed parameter and receive the result back from a thread after it has finished executing. Asynchronous delegate solves this limitation, allowing any number of typed arguments to be passed in both directions. Furthermore, un-handled exceptions on asynchronous delegates are conveniently rethrown on the original thread (or more accurately, the thread that calls EndInvoke
), and so they don’t need explicit handling.
How to Use Asynchronous Delegates
using System;
using System.Threading;
namespace TestConsole
{
class Program
{
public static void Main(string[] args)
{
Func<string, int, string > method = DoLongTask;
IAsyncResult doLongTaskResult1 = method.BeginInvoke("value1", 1234, null, null);
IAsyncResult doLongTaskResult2 = method.BeginInvoke("value1", 1234, DoLongTaskCompleted, method);
string result = method.EndInvoke(doLongTaskResult1);
Console.WriteLine("Status of DoLongTask is : " + result);
Console.WriteLine("Main thread ends");
Console.ReadKey();
}
public static string DoLongTask(string param1, int param2)
{
Console.WriteLine("Thread is background : {0}", Thread.CurrentThread.IsBackground);
Console.WriteLine("Input parameter : {0} and {1}", param1, param2);
return "Success";
}
public static void DoLongTaskCompleted(IAsyncResult asyncResult)
{
var target = (Func<string, int, string>) asyncResult.AsyncState;
var result = target.EndInvoke(asyncResult);
Console.WriteLine("DoLongWork has completed and result is {0}", result);
}
}
}
BeginInvoke
returns immediately to the caller without waiting for the asynchronous call to complete. You can perform other activities in parallel while the pooled thread is working. When you need the results, simply call EndInvoke
on the delegate, passing in the saved IAsyncResult
object.
When we call EndInvoke
, it waits for the asynchronous delegate to finish executing. It receives the return value (as well as any ref
or out
parameters). It throws any unhandled exception back to the calling thread.
If you need to call some method after asynchronous method has completed, then you can pass the callback handler method, which accepts IAsyncResult
object, while calling BeginInvoke
method. This allows the instigating thread to “forget” about the asynchronous delegate, but it requires a bit of extra work at the callback end as you can see in the given example.
The final argument to BeginInvoke
is a user state object that populates the AsyncState
property of IAsyncResult
. It can contain anything you like; in this case, we’re using it to pass the method delegate to the completion callback, so we can call EndInvoke
on it.
Thread Pooling – BackgroundWorker >>