: C# 2008 Programmer

Asynchronous Callbacks

Asynchronous Callbacks

Callbacks are most useful if they are asynchronous. The callback illustrated in the previous example is synchronous, that is, the functions are called sequentially. If the AddTwoNumbers() function takes a long time to execute, all the statements after it will block. Figure7-1 shows the flow of execution when the callback is synchronous.


Figure 7-1

A better way to organize the program is to call the AddTwoNumbers() method asynchronously, as shown in Figure 7-2. Calling a function asynchronously allows the main program to continue executing without waiting for the function to return.


Figure 7-2

In this asynchronous model, when the AddTwoNumbers() function is called, the statement(s) after it can continue to execute. When the function finishes execution, it calls the ResultCallback() function.

Here's the rewrite of the previous program, using an asynchronous callback:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.Remoting.Messaging;
namespace Delegates {
class Program {
//---delegate to the AddTwoNumbers() method---
delegate int MethodDelegate(int num1, int num2);
static void Main(string[] args) {
//---assign the delegate to point to AddTwoNumbers()---
MethodDelegate del = AddTwoNumbers;
//---creates a AsyncCallback delegate---
AsyncCallback callback = new AsyncCallback(ResultCallback);
//---invoke the method asychronously---
Console.WriteLine("Invoking the method asynchronously...");
IAsyncResult result = del.BeginInvoke(5, 3, callback, null);
Console.WriteLine("Continuing with the execution...");
Console.ReadLine();
}
//---method to add two numbers---
static private int AddTwoNumbers(int num1, int num2) {
//---simulate long execution---
System.Threading.Thread.Sleep(5000);
return num1 + num2;
}
static private void ResultCallback(IAsyncResult ar) {
MethodDelegate del =
(MethodDelegate)((AsyncResult)ar).AsyncDelegate;
//---get the result---
int result = del.EndInvoke(ar);
Console.WriteLine("Result of addition is: " + result);
}
}
}

First, you define a delegate type so that you can point to the AddTwoNumbers() method:

delegate int MethodDelegate(int num1, int num2);

Then create a delegate, and assign it to point to the AddTwoNumbers() method:

//---assign the delegate to point to AddTwoNumbers()---
MethodDelegate del = AddTwoNumbers;

Next, define a delegate of type AsyncCallback:

//---creates a AsyncCallback delegate---
AsyncCallback callback = new AsyncCallback(ResultCallback);

The AsyncCallback is a delegate that references a method to be called when an asynchronous operation completes. Here, you set it to point to ResultCallback (which you will define later).

To call the AddTwoNumbers() methods asynchronously, you use the BeginInvoke() method of the del delegate, passing it two integer values (needed by the AddTwoNumbers() method), as well as a delegate to call back when the method finishes executing:

//---invoke the method asynchronously---
Console.WriteLine("Invoking the method asynchronously...");
IAsyncResult result = del.BeginInvoke(5, 3, callback, null);
Console.WriteLine("Continuing with the execution...");

The BeginInvoke() method calls the delegate asynchronously, and the next statement continues execution after the async delegate is called. This method returns a variable of type IAsyncResult to represent the status of an asynchronous operation.

To obtain the result of the calculation, you define the ResultCallback() method, which takes in an argument of type IAsyncResult:

static private void ResultCallback(IAsyncResult ar) {
MethodDelegate del =
(MethodDelegate)((AsyncResult)ar).AsyncDelegate;
//---get the result---
int result = del.EndInvoke(ar);
Console.WriteLine("Result of addition is: " + result);
}

Within the ResultCallback() method, you first obtain the delegate to the AddTwoNumbers() method by using the AsyncDelegate property, which returns the delegate on which the asynchronous call was invoked. You then obtain the result of the asynchronous call by using the EndInvoke() method, passing it the IAsyncResult variable (ar).

Finally, to demonstrate the asynchronous calling of the AddTwoNumbers() method, you can insert a Sleep() statement to delay the execution (simulating long execution):

static private int AddTwoNumbers(int num1, int num2) {
//---simulate long execution---
System.Threading.Thread.Sleep(5000);
return num1 + num2;
}

Figure 7-3 shows the output of this program.


Figure 7-3

When using asynchronous callbacks, you can make your program much more responsive by executing different parts of the program in different threads.

Chapter 10 discusses more about threading.


: 1.345. /Cache: 3 / 1