NGWS SDK Documentation  

This is preliminary documentation and subject to change.
To comment on this topic, please send us email at ngwssdk@microsoft.com. Thanks!

Async Design Pattern

As an example, consider the following server class

class PrimeFactorizer
{
public boolean Factorize(unsigned long factorizableNum,  
            ByRef unsigned long primefactor1,
            ByRef unsigned long primefactor2)
      {
         // Ensure that the given number is factorizable to prime numbers
         …..
         …..
         if(IsPrimeFactorizable == false)
         {
            primefactor1 = primefactor2 = 0;
            return(false);
         }

         // Factorize
         ……
         primefactor1 = …..;
         primefactor2 = …..;

         return(true);
}
}

The following code snippet shows client defining a pattern for invoking Factorize method asynchronously:

delegate FactorizingDelegate(unsigned long factorizableNum,  
       ByRef unsigned long primefactor1,
       ByRef unsigned long primefactor2);
PrimeFactorizer pf = new PrimeFactorizer();
FactorizingDelegate fd = new FactorizingDelegate(pf.Factorize);

Compiler will define the following FactorizingDelegate class after parsing its definition at the first line above:

   class FactorizingDelegate extends delegate
   {
public boolean Invoke(unsigned long factorizableNum,  
         ByRef unsigned long primefactor1,
         ByRef unsigned long primefactor2);
public IAsyncResult BeginInvoke(unsigned long factorizableNum,  
                        ByRef unsigned long primefactor1,
                        ByRef unsigned long primefactor2,
               AsyncCallbackDelegate cb);
public boolean EndInvoke(ByRef unsigned long primefactor1,
              ByRef unsigned long primefactor2,
              IAsyncResult ar);
}

The following classes are defined inside classlibs:

delegate AsyncCallback (IAsyncResult ar);

public interface IAsyncResult
    {
    
        /**
         * True if the asynchronous operation has been completed.
         */
        bool IsCompleted { get; }
    
        /**
         * Handle to block on for the results
         */
        WaitHandle AsyncWaitHandle { get; }
    
        /**
         * The delegate object on which the async call was invoked.
         */
        Object     AsyncObject     { get; }
    
        /**
         * The state object passed in via BeginInvoke.
         */
        Object     AsyncState      { get; }
       
        
        /** true if the call completed synchronously
        */
        bool       CompletedSynchronously { get; }

Note that the object that implements IAsyncResult must be a waitable object and its underlying synchronization primitive should be signaled after the call is canceled or completed. This enables the client to wait for the call to complete instead polling. Runtime is supplying a number of waitable objects that mirror Win32 synchronization primitives. It also will be supplying the methods that support waiting for such synchronization objects to become signaled with “any” or “all” semantics. Such methods will be context aware to avoid deadlocks.

The Cancel method is a request to cancel processing of the method after the desired timeout period has expired. Note that it is only a request by the client and server is recommended to honor it. Further, client should not assume that the server has stopped processing the request completely after it got the notification that the method has been canceled. In other words, the client is recommended not destroy the resources such as file objects as the server may be actively using them. The IsCancelled property will be set to “true” if the call was canceled and IsCompleted property will be set to “true” after the server has completed processing of the call. It is illegal for the server to use any client supplied resources outside of the agreed upon sharing semantics after it sets the IsCompleted property to “true”. Thus, it is safe for the client to destroy the resources after IsCompleted property returns “true”.

The Server property returns the server object that provided the IAsyncResult.

The following code snippet demonstrates the client-side programming model for invoking the Factorize method asynchronously:

class FactorizeCallback
{
public FactorizeCallback(unsigned long number)
{
   _ulNumber = number;
}
// Note the qualifier one-way. See last paragraph of this section for
// its explanation.
public one-way boolean FactorizedResults(IAsyncResult ar)
   {
unsigned long factor1, factor2; 
      FactorizingDelegate fd = ar.AsyncObject;
      fd.EndInvoke(factor1, factor2, ar);

// Output results
Console.Writeline(“Factors of” + _ulNumber + “:” + factor1 + “ ” + 
   factor2);
   }

   private unsigned long _ulNumber
}

// Client code
delegate FactorizingDelegate(unsigned long factorizableNum, 
       ByRef unsigned long primefactor1,
       ByRef unsigned long primefactor2);
PrimeFactorizer pf = new PrimeFactorizer();
FactorizingDelegate fd = new FactorizingDelegate(pf.Factorize);

// --------------------------------------------------------------------------------------------------------
// Async Variation 1
unsigned long factorizableNum = 1000589023, temp; 

// Define the asynccallback delegate
FactorizeCallback fc = new FactorizeCallback(factorizableNum);
AsyncCallbackDelegate cb = new AsyncCallbackDelegate(fc.FactorizedResults);

// Asynchronously invoke the Factorize method on pf
// Note: If we have pure out parameters, we do not need temp
fd.BeginInvoke(factorizableNum, temp, temp, cb); 

// Proceed to do other work
……


// --------------------------------------------------------------------------------------------------------
// Async Variation 2
// Asynchronously invoke the Factorize method on pf
// Note: If we have pure out parameters, we do not need temp
unsigned long factorizableNum = 1000589023, temp, factor1, factor2; 
IAsyncResult ar = fd.BeginInvoke(factorizableNum, temp, temp, NULL); 

// Do other work
……

// Wait for the callback
SynchronizationServices.WaitForSingleObject(ar);

// Output results
fd.EndInvoke(factor1, factor2, ar);
Console.Writeline(“Factors of” + factorizableNum + “:” + factor1 + “ ” + factor2);

Note that if the FactorizeCallback is a context-bound class that requires synchronized/thread- affinity context, the callback is dispatched through the context dispatcher infrastructure. In other words, the callback itself may execute asynchronously with respect to its caller for such contexts. That is precisely the semantics of the one-way qualifier on method signatures. It means that any such method call may execute synchronously or asynchronously with respect to caller and the caller cannot make any assumptions about completion of such a call when execution control returns to it.

Also, calling EndInvoke before the asynchronous operation is complete will block the caller. Calling it second time with the same AsyncResult is undefined.