Asynchronous Delegates

Polling

One technique is to poll and check if the delegate has already finished its work.

The delegate class provides the methode BeginInvoke(), where you can pass the input parameters defined with the delegate type. BeginInvoke() always has two additional parameters of type AsyncCallBack and object, which are disucssed later.

What's important now is the return type, BeginInvoke():IAsyncResult. With IAsyncResult, you can get information about the delegate, and also verify if the delegate has already finished its work, as is done with IsCompeleted property.

 1 using System;
 2 using System.Threading;
 3 
 4 namespace 异步委托
 5 {
 6     public delegate int TakesAWhileDelegate(int data, int ms);
 7 
 8     class Program
 9     {
10         static void Main(string[] args)
11         {
12             TakesAWhileDelegate dl = TakesAWhile;
13             IAsyncResult ar = dl.BeginInvoke(1, 3000, null, null);
14             while (!ar.IsCompleted)
15             {
16                 Console.Write(".");
17                 Thread.Sleep(50);
18             }
19             int result = dl.EndInvoke(ar);
20             Console.WriteLine("result: {0}", result);
21             Console.Read();
22         }
23 
24         static int TakesAWhile(int data, int ms)
25         {
26             Console.WriteLine("TakesAWhile started");
27             Thread.Sleep(ms);
28             Console.WriteLine("TakesAWhile complted");
29             return ++data;
30         }
31     }
32 }
Polling

When you run the application, you can see the main thread and the thread of the delegate running concurrently, and the main thread stops looping after the delegate thread completes:

Instead of examining if the delegate is completed, you can just invoke the EndInvoke() method of the delegate type after you are finished with the work that can be done by the main thread. EndInovke() itseld waits until the delegate has completed its work.

Wait Handle

Another way to wait for the result from the asynchronous delegate is by using the wait handle that is associated with IAsyncResult.

You can access the wait handle with the AsyncWaitHandle property. This property returns an object of type WaitHandle, where you can wait for the delegate thread to finish its work.

The method WaitOne() accepts a timeout with the optional first parameter, where you can define the maximum time you want to wait; here, it is set to 50 millisecond. If a timeout occurs, WaitOne() returns false and the while loop continue. If the wait is successful, the while loop is exited with a break, and the result is received with the delegate EndInovke() method. From the UI standpoint the result is similar to the previous sample; just the wait is done in a different manner.

 1 using System;
 2 using System.Threading;
 3 
 4 namespace 异步委托
 5 {
 6     public delegate int TakesAWhileDelegate(int data, int ms);
 7 
 8     class Program
 9     {
10         static void Main(string[] args)
11         {
12             TakesAWhileDelegate dl = TakesAWhile;
13             IAsyncResult ar = dl.BeginInvoke(1, 3000, null, null);
14             while (true)
15             {
16                 Console.Write(".");
17                 if (ar.AsyncWaitHandle.WaitOne(50, false))
18                 {
19                     Console.WriteLine("Can get the result now");
20                     break;
21                 }
22             }
23             int result = dl.EndInvoke(ar);
24             Console.WriteLine("result: {0}", result);
25             Console.Read();
26         }
27 
28         static int TakesAWhile(int data, int ms)
29         {
30             Console.WriteLine("TakesAWhile started");
31             Thread.Sleep(ms);
32             Console.WriteLine("TakesAWhile complted");
33             return ++data;
34         }
35     }
36 }
Wait Handle

Asynchronous Callback

The third version of waiting for the result from the delegate uses an asynchronous callback.

With the third parameter of BeginInvoke(), you can pass a method that fulfills the requirements of the AsyncCallback delegate. The AsyncCallback delegate defines a parameter of IAsnycResult and a void return type. Here, the address of the method TakesAWhileCompleted is assigned to the third parameter, which fulfills the requirments of the AsyncCallback delegate.

For the last parameter, you can pass any object for accessing it from the callback method. It is useful to pass the delegate instance itself, so the callback method can use it to get the result of the asynchronous method.

The method TakesAWhileCompleted() is invoked as soon as the delegate TakesAWhileDelegate has completed its work. There is no need to wait for a result inside the main thread. However, you may not end the main thread before the work of the delegate threads are finished, unless you don't have a problem with delegate threads stopping when the main thread ends.

The method TakesAWhileCompleted() is defined with the parameter and return type specified by the AsyncCallback delegate. The last parameter passed with the BeginInovke() method can be read here by using ar.AsyncState. With the TakesAWhileDelegate, you can invoke the EndInovke method to get the result.

 1 using System;
 2 using System.Diagnostics;
 3 using System.Threading;
 4 
 5 namespace 异步委托
 6 {
 7     public delegate int TakesAWhileDelegate(int data, int ms);
 8 
 9     class Program
10     {
11         static void Main(string[] args)
12         {
13             TakesAWhileDelegate dl = TakesAWhile;
14             dl.BeginInvoke(1, 3000, TakesAWhileCompleted, dl);
15             for (int i = 0; i < 100; i++)
16             {
17                 Console.Write(".");
18                 Thread.Sleep(50);
19             }
20             Console.Read();
21         }
22 
23         static void TakesAWhileCompleted(IAsyncResult ar)
24         {
25             if (ar == null)
26             {
27                 throw new ArgumentNullException("IAsyncResult is null");
28             }
29 
30             TakesAWhileDelegate dl = ar.AsyncState as TakesAWhileDelegate;
31             Trace.Assert(dl != null, "Invaild object type");
32 
33             int result = dl.EndInvoke(ar);
34             Console.WriteLine("result: {0}", result);
35         }
36 
37         static int TakesAWhile(int data, int ms)
38         {
39             Console.WriteLine("TakesAWhile started");
40             Thread.Sleep(ms);
41             Console.WriteLine("TakesAWhile complted");
42             return ++data;
43         }
44     }
45 }
Asynchronous Callback

Instead of defining a separate method and passing it to the BeginInvoke() method, Labmda expressions can be used.

The parameter ar is type of IAsyncResult. With the implementation, there is no need to assign a value to the last parameter of the BeginInvoke() method because the Lambda expression can directly access variable dl that is in the outer scope.

However, the implementation block of the Lambda expression is still invoked from the thread of the delegate, which might not be clear immediately when defining the method in this way.

 1 using System;
 2 using System.Threading;
 3 
 4 namespace 异步委托
 5 {
 6     public delegate int TakesAWhileDelegate(int data, int ms);
 7 
 8     class Program
 9     {
10         static void Main(string[] args)
11         {
12             TakesAWhileDelegate dl = TakesAWhile;
13             dl.BeginInvoke(1, 3000,
14                 ar =>
15                 {
16                     int result = dl.EndInvoke(ar);
17                     Console.WriteLine("result: {0}", result);
18                 },
19                 null);
20             for (int i = 0; i < 100; i++)
21             {
22                 Console.Write(".");
23                 Thread.Sleep(50);
24             }
25             Console.Read();
26         }
27 
28         static int TakesAWhile(int data, int ms)
29         {
30             Console.WriteLine("TakesAWhile started");
31             Thread.Sleep(ms);
32             Console.WriteLine("TakesAWhile complted");
33             return ++data;
34         }
35     }
36 }
Asynchronous Callback with Lambda

Further

The programming model and all of these options with asynchronous delegates ---- polling, wait handle, and asynchronous callback ---- are not only available with delegates. The same programming model ---- this is the asynchronous pattern ---- can be found in various places in the .NET Framework.

For example, you can send an HTTP Web request asynchronously with the BeginGetResponse() method of the HttpWebRequest class. You can send an asynchronous request to the database with the BeginExecuteReader() of the SqlCommand class. The paramters similar to those of the BeginInovek() class of the delegate, and you can use the same mechanisms to get the result.

posted @ 2013-06-16 15:00  骚丝扣特  阅读(121)  评论(0编辑  收藏  举报