Call the synchronous method of in an asynchronous manner

  • 2020-05-19 05:38:52
  • OfStack

Description:

Asynchronous delegate calls, namely the BeginInvoke and EndInvoke methods, are not supported in.NET Compact Framework.

The BeginInvoke method starts the asynchronous call. This method has the same parameters as the method you need to execute asynchronously, along with two other optional parameters. The first parameter is an AsyncCallback delegate that references the method to be invoked when the asynchronous call completes. The second parameter is a user-defined object that passes the information into the callback method. Instead of waiting for the asynchronous call to complete, BeginInvoke returns immediately. BeginInvoke returns an IAsyncResult that can be used to monitor the progress of an asynchronous call.

The EndInvoke method retrieves the result of the asynchronous call. This method can be called at any time after BeginInvoke is called. If the asynchronous call is not complete, EndInvoke will block the calling thread until the asynchronous call is complete. The parameters for EndInvoke include the out and ref parameters for the method you want to execute asynchronously (in Visual Basic) < Out > ByRef and ByRef) and IAsyncResult returned by BeginInvoke.

Description:

The IntelliSense function in Visual Studio 2005 displays the parameters of BeginInvoke and EndInvoke. If you are not using Visual Studio or similar tools, or if you are using C# with Visual Studio 2005, see instructions for the asynchronous programming overview to get the parameters defined for these methods.

The code examples in this topic demonstrate four common methods for making asynchronous calls using BeginInvoke and EndInvoke. After calling BeginInvoke, you can do the following:

Do something and then call EndInvoke 1 to block until the call is complete.

Get WaitHandle using the IAsyncResult.AsyncWaitHandle property, use its WaitOne method 1 to block execution until an WaitHandle signal is issued, and then call EndInvoke.

Poll the IAsyncResult returned by BeginInvoke to determine when the asynchronous call is completed, and then call EndInvoke.

Pass the delegate for the callback method to BeginInvoke. When the asynchronous call is complete, the method is executed on the ThreadPool thread. The callback method calls EndInvoke.

Important note:

Whatever method you use, call EndInvoke to complete the asynchronous call.

Define test methods and asynchronous delegates

The following code example demonstrates various ways to invoke the same long-running method, TestMethod, asynchronously. The TestMethod method displays a console message indicating that the method has started processing, sleeps for a few seconds, and then ends. TestMethod has one out parameter, which is used to demonstrate how this parameter is added to the BeginInvoke and EndInvoke signatures. You can handle the ref parameter in the same way.

The following code example demonstrates the definition of TestMethod and a delegate named AsyncMethodCaller that can be used to invoke TestMethod asynchronously. To compile the code sample, you must include the definition of TestMethod and the AsyncMethodCaller delegate.

C#


using System;
using System.Threading; 
namespace AsyncTest
{
    public class AsyncDemo 
    {
        // methods 1
        public string TestMethod(int callDuration, out int threadId) 
        {
            Console.WriteLine("Test method begins.");
            Thread.Sleep(callDuration);
            threadId = Thread.CurrentThread.ManagedThreadId;
            return String.Format("My call time was {0}.", callDuration.ToString());
        }
// methods 2
public float Addxy(float x, float y)
        {
            return x * y;
        }
    }
    // Defines two delegates corresponding to a method that takes the same arguments as the method 1 to , The declaration of the delegate is written in the calling class as well 1 Kind, not limited 
    public delegate string AsyncMethodCaller(int callDuration, out int threadId);
    public delegate float AsyncMethodCaller2(float x, float y);
}

Use EndInvoke to wait for the asynchronous call

The easiest way to execute a method asynchronously is to start executing the method by calling the BeginInvoke method of the delegate, do something on the main thread, and then call the EndInvoke method of the delegate. EndInvoke may block the calling thread because the method does not return until the asynchronous call is completed. This approach is ideal for performing file or network operations.

Important note:

Because EndInvoke can block, this method should not be called from a thread serving the user interface.

C#


using System;
using System.Threading;
namespace AsyncTest
{
    public class AsyncMain 
    {
        public static void Main() 
        {
            // The asynchronous method puts the thread id here.
            int threadId;
            // instantiation .
            AsyncDemo ad = new AsyncDemo();
            //  Define the entrusted 
            AsyncMethodCaller caller = new AsyncMethodCaller(ad.TestMethod);
            // The method is called by delegate, and the callback function is null
            IAsyncResult result = caller.BeginInvoke(3000, 
                out threadId, null, null);
            Thread.Sleep(0);
            Console.WriteLine("Main thread {0} does some work.",
                Thread.CurrentThread.ManagedThreadId);
            // Call EndInvoke to wait for the asynchronous call to complete, blocks 
            // and to retrieve the results.
            string returnValue = caller.EndInvoke(out threadId, result);
            Console.WriteLine("The call executed on thread {0}, with return value \"{1}\".",
                threadId, returnValue);
        }
    }
}

Use WaitHandle to wait for the asynchronous call

You can get WaitHandle using the AsyncWaitHandle property of IAsyncResult returned by BeginInvoke. The WaitHandle signal is sent when the asynchronous call is completed, and you can wait for it by calling the WaitOne method.

If you use WaitHandle, you can perform other processing before or after the asynchronous call completes, but before retrieving the result by calling EndInvoke.

Description:

The wait handle is not automatically closed when EndInvoke is called. If all references to the waiting handle are freed, system resources will be freed when the garbage collection function recycles the waiting handle. To release system resources immediately after the wait handle is used, call the WaitHandle.Close method to release the wait handle. Garbage collection is more efficient when you explicitly release releasable objects.

C#


using System;
using System.Threading;
namespace AsyncTest
{
    public class AsyncMain 
    {
        static void Main() 
        {
            // The asynchronous method puts the thread id here.
            int threadId;
            // instantiation 
            AsyncDemo ad = new AsyncDemo();
            // Define the entrusted .
            AsyncMethodCaller caller = new AsyncMethodCaller(ad.TestMethod);
            // call 
            IAsyncResult result = caller.BeginInvoke(3000, 
                out threadId, null, null);
            Thread.Sleep(0);
            Console.WriteLine("Main thread {0} does some work.",
                Thread.CurrentThread.ManagedThreadId);
            // Wait for the WaitHandle to become signaled.
            result.AsyncWaitHandle.WaitOne();
            // Perform additional processing here.
            // Call EndInvoke to retrieve the results.
            string returnValue = caller.EndInvoke(out threadId, result);
            // Close the wait handle.
            result.AsyncWaitHandle.Close();
            Console.WriteLine("The call executed on thread {0}, with return value \"{1}\".",
                threadId, returnValue);
        }
    }
}

/* output is as follows:
Main thread 1 does some work.
Test method begins.
The call executed on thread 3, with return value "My call time was 3000.".
*/

Polling the asynchronous call is complete

You can use the IsCompleted property of IAsyncResult returned by BeginInvoke to find out when the asynchronous call has completed. You can do this when you make an asynchronous call from a service thread in the user interface. Polling completion allows the calling thread to continue execution while the asynchronous call is executing on the ThreadPool thread.

C#C++VB


using System;
using System.Threading;
namespace AsyncTest
{
    public class AsyncMain 
    {
        static void Main() {
            // The asynchronous method puts the thread id here.
            int threadId;
            // instantiation .
            AsyncDemo ad = new AsyncDemo();
            // Commissioned by the statement 
            AsyncMethodCaller caller = new AsyncMethodCaller(ad.TestMethod);
            // call .
            IAsyncResult result = caller.BeginInvoke(3000, 
                out threadId, null, null);
            // polling .
            while(result.IsCompleted == false) {
                Thread.Sleep(250);
                Console.Write(".");
            }
            // Take the result .
            string returnValue = caller.EndInvoke(out threadId, result);
            Console.WriteLine("\nThe call executed on thread {0}, with return value \"{1}\".",
                threadId, returnValue);
        }
    }
}

/ * output:
Test method begins.
.............
The call executed on thread 3, with return value "My call time was 3000.".
*/

The callback method is executed when the asynchronous call is complete

If the thread that started the asynchronous call does not need to be the one that processes the result, the callback method can be executed when the call is complete. The callback method is executed on the ThreadPool thread.

To use the callback method, you must pass the AsyncCallback delegate representing the callback method to BeginInvoke. You can also pass an object that contains information to be used by the callback method. In the callback method, you can cast IAsyncResult (only 1 parameter of the callback method) to an AsyncResult object. You can then use the AsyncResult.AsyncDelegate property to get the delegate that has been used to start the call so that EndInvoke can be called.

Notes on examples:

The threadId parameter of TestMethod is the out parameter (in Visual Basic is the out parameter < Out > ByRef), so TestMethod never USES the input value for this parameter. A dummy variable is passed to the BeginInvoke call. If the threadId parameter is the ref parameter (ByRef in Visual Basic), then the variable must be a class level field so that it can be passed to both BeginInvoke and EndInvoke.

The state information passed to BeginInvoke is a format string that the callback method USES to format the output message. Because it is passed as the type Object, the state information must be cast to the correct type to be used.

The callback is made on the ThreadPool thread. The ThreadPool threads are background threads that do not keep the application running after the main thread ends, so the main thread for the example must sleep long enough for the callback to complete.

C#


using System;
using System.Threading;
using System.Runtime.Remoting.Messaging;
namespace AsyncTest
{
    public class AsyncMain 
    {
        static void Main() 
        {
            // Instantiate the class .
            AsyncDemo ad = new AsyncDemo();
            // Instance two different delegates, each corresponding to a different method .
            AsyncMethodCaller caller = new AsyncMethodCaller(ad.TestMethod);
AsyncMethodCaller2 caller2 = new AsyncMethodCaller2(ad.Addxy);
            // The threadId parameter of TestMethod is an out parameter, so
            // its input value is never used by TestMethod. Therefore, a dummy
            // variable can be passed to the BeginInvoke call. If the threadId
            // parameter were a ref parameter, it would have to be a class-
            // level field so that it could be passed to both BeginInvoke and 
            // EndInvoke.
            int dummy = 0;
            //  Specifies a callback method when invoked, which is automatically invoked after asynchronous execution to obtain the result of the execution 
            IAsyncResult result = caller.BeginInvoke(3000,
                out dummy, 
                new AsyncCallback(CallbackMethod),
                "The call executed on thread {0}, with return value \"{1}\".");
caller2.BeginInvoke(2, 3, CallbackMethod2, "this is add");
            Console.WriteLine("The main thread {0} continues to execute...", 
                Thread.CurrentThread.ManagedThreadId);
            Thread.Sleep(4000);
            Console.WriteLine("The main thread ends.");
        }
        // The callback method must have the same signature as the
        // AsyncCallback delegate.
        private void CallbackMethod(IAsyncResult ar) 
        {
            // Retrieve the delegate.
            AsyncResult result = (AsyncResult) ar;
   // Cast to the corresponding delegate object 
            AsyncMethodCaller caller = (AsyncMethodCaller) result.AsyncDelegate;
            // Retrieve the format string that was passed as state 
            // information.
            string formatString = (string) ar.AsyncState;
            // Define a variable to receive the value of the out parameter.
            // If the parameter were ref rather than out then it would have to
            // be a class-level field so it could also be passed to BeginInvoke.
            int threadId = 0;
            // Call EndInvoke to retrieve the results.
            string returnValue = caller.EndInvoke(out threadId, ar);

            // Use the format string to format the output message.
            Console.WriteLine(formatString, threadId, returnValue);
        }
private void CallbackMethod2(IAsyncResult ar)
        {
            // Retrieve the delegate.
            AsyncResult result = (AsyncResult)ar;
// Cast to the corresponding delegate object 
            AsyncMethodCaller2 caller = (AsyncMethodCaller2)result.AsyncDelegate;
            //  To obtain state 
            string formatString = (string)ar.AsyncState;
            // Invoke the asynchronously completed method to get the execution result 
            string returnValue = caller.EndInvoke(ar).ToString();
// This way is in windows Used when the application assigns a value to a control because the control cannot be manipulated in a non-creation thread 
            this.Invoke(new Action<string>((u) => tb_datainfo.Text += u), returnValue);
            //tb_datainfo.Text = caller.EndInvoke(out threadId, ar);
            // Use the format string to format the output message.
            //Console.WriteLine(formatString, threadId, returnValue);
        }
    }
    }
} 


Related articles: