DekGenius.com
[ Team LiB ] Previous Section Next Section

Recipe 15.4 Polling an Asynchronous Delegate

Problem

While an asynchronous delegate is executing, you need to continuously poll it to see whether it has completed. This ability is useful when you need to monitor the length of time it takes the asynchronous delegate to execute or if you need to monitor other objects in the system in parallel with this asynchronous delegate, possibly to determine which object finishes first, second, third, and so on. It can also be useful when performing a continuous task, such as displaying an indicator to the user that the asynchronous operation is still running.

Solution

Use the IsCompleted property of the IAsyncResult interface to determine when the asynchronous call has completed. The following example shows how this is accomplished:

using System;
using System.Threading;

public class AsyncAction
{
    public void PollAsyncDelegate( )
    {
        // Set up the delegate
        AsyncInvoke method1 = new AsyncInvoke(TestAsyncInvoke.Method1);
        // Define the AsyncCallback delegate.
        AsyncCallback callBack = new AsyncCallback(TestAsyncInvoke.CallBack);
        IAsyncResult asyncResult = method1.BeginInvoke(callBack,method1);

        while (!asyncResult.IsCompleted)
        {
            // give up the CPU for 1 second
            Thread.Sleep(1000);
            Console.Write('.');
        }
        Console.WriteLine("Finished Polling");

        try
        {
            int retVal = method1.EndInvoke(asyncResult);
            Console.WriteLine("retVal: " + retVal);
        }
        catch (Exception e)
        {
            Console.WriteLine(e.ToString( ));
        }
    }
}

The following code defines the AsyncInvoke delegate and the asynchronously invoked static method TestAsyncInvoke.Method1:

public delegate int AsyncInvoke( );

public class TestAsyncInvoke
{
    public static int Method1( )
    {
        Console.WriteLine("Invoked Method1");
        return (1);
    }

    public static void CallBack(IAsyncResult ar)
    {
        // Retrieve the delegate.
        AsyncInvoke ai = (AsyncInvoke) ar.AsyncState;

        // Call EndInvoke to retrieve the results.
        int retVal = ai.EndInvoke(ar);
        Console.WriteLine("retVal: " + retVal);
    }
}

Discussion

The delegate, AsyncInvoke, is invoked asynchronously using its BeginInvoke method. The BeginInvoke method returns an IAsyncResult object, which allows access to the result information from an asynchronous operation.

If the delegate were to accept a string and an int, in this order, the BeginInvoke method would be defined as this:

public IAsyncResult BeginInvoke(string s, int i, AsyncCallback callback, 
                                object state)

For this recipe the callback and state parameters are set to null. The callback parameter could call back at completion into the code that invoked it, but for this example, it is a no-op.

To poll for the completion of the method1 delegate, we get the IsCompleted property of the IAsyncResult object that is returned by the BeginInvoke method. The IsCompleted property returns true if the method1 delegate has completed its operation or false if it has not. This property can be called continuously within a loop to check whether the delegate has finished.

Once the method1 delegate has finished its asynchronous processing, the results of the operation can be retrieved through a call to the EndInvoke method. The compiler also creates this method dynamically, so that the return value of the delegate can be accessed through the EndInvoke method—as well as any out or ref parameters that the delegate accepts as parameters.

The EndInvoke method returns an object of the same type as the return value of the asynchronous delegate. An EndInvoke method called on a delegate of the following signature:

public delegate long Foo(ref int i, out string s, bool b);

will be defined as follows:

public long EndInvoke(ref int i, out string s, IAsyncResult result)

Notice that the return type is a long and only the ref and out parameters of the original delegate are in the signature for this method. The EndInvoke method contains only the output parameters of the delegate or those marked as ref or out.

If the asynchronous delegate throws an exception, the only way to obtain that exception object is through the EndInvoke method. The EndInvoke method should be wrapped in an exception handler.


Once the while loop of the PollAsyncDelegate method in this recipe is exited—meaning that the asynchronous delegate has completed—the EndInvoke method can be safely called to retrieve the return value of the delegate as well as any ref or out parameter values. If you want to obtain these values, you must call the EndInvoke method; however, if you do not need any of these values, you may leave out the call to the EndInvoke method.

See Also

See the "IAsyncResult Interface," "AsyncResult Class," "BeginInvoke Method," and "EndInvoke Method" topics in the MSDN documentation.

    [ Team LiB ] Previous Section Next Section