Thread, Thread, Thread… Execute a Method Asynchronously.

Problem: You need to start execution of a method and continue with other tasks while the method runs on a separaete thread. After the mehtod completes, you need to retrive the method’s return value.

Solution: Declare a delegate with the same signature as the method you want to execute. Create an instance of the delegate that references the method. Call the BeginInvoke method of the delegate instance to start executing your method. Use the EndInvoke method to determine the method’s status as well as obtain the method’s return value if complete.

Sample Code:

The following code demonstrates how to use the asynchronus execution pattern. It uses a delegate named AsyncExampleDelegate to execute a method using a configurable delay (produced using Thread.Sleep ). The example contains the following five methods that demonstrate the various approaches to handling asynchronous method completion:

  • BlockingExample: This method excutes LongRunningMethod asynchronously and continues with a limited set of processing. Once this processing is complete, BlockingExample blocks until LongRunningMethod complete. To block, BlockingExample calls the EndInvoke method of the AsyncExampleDelegate delegate instance. If LongRunningMethod has already finished, EndInvoke returns immediately; otherwise, BlockingExample blocks until LongRunningMethod completes.
  • PollingExample: This method executes LongRunningMethod asynchronously and then enters a polling loop until LongRunningMethod completes. PollingExample test the IsCompleted property of the IAsyncResult instance retuernd by BeginInvoke to determine whther LongRunningMethod is complete; otherwise, PollingExample calls Thread.Sleep.

using System;
using System.Text;
using System.Threading;
using System.Collections;

namespace ConsoleApplication6
{
    class Program
    {

        private static void TraceMsg(DateTime time, string msg)
        {
            Console.WriteLine("[{0,3}/{1}] – {2} : {3}",
                Thread.CurrentThread.ManagedThreadId,
                Thread.CurrentThread.IsThreadPoolThread ? "pool" : "fore",
                time.ToString("HH:mm:ss.ffff"), msg);
        }

        public delegate DateTime AsyncExampleDelegate(int delay, string name);

        public static DateTime LongRunningMethod(int delay, string name)
        {
            TraceMsg(DateTime.Now, name + " example – tread starting.");

            Thread.Sleep(delay);

            TraceMsg(DateTime.Now, name + " example – thread stopping.");

            return DateTime.Now;
        }

        public static void BlockingExample()
        {
            Console.WriteLine(Environment.NewLine + "*** Running Blocking Example ***");

            AsyncExampleDelegate longRunningMethod = LongRunningMethod;

            IAsyncResult asyncResult = longRunningMethod.BeginInvoke(2000, "Blocking", null, null);

            for (int count = 0; count < 3; count++)
            {
                TraceMsg(DateTime.Now, "Continue processing until ready to block…");

                Thread.Sleep(200);
            }

            TraceMsg(DateTime.Now, "Blocking until method is complete…");

            DateTime completion = DateTime.MinValue;

            try
            {
                completion = longRunningMethod.EndInvoke(asyncResult);
            }
            catch
            {

            }

            TraceMsg(completion, "Blocking example complete…");
        }

        public static void PollingExample()
        {
            Console.WriteLine(Environment.NewLine + "*** Running Polling Example ***");

            AsyncExampleDelegate longRunningMethod = LongRunningMethod;

            IAsyncResult asyncResult = longRunningMethod.BeginInvoke(2000, "Polling", null, null);

            TraceMsg(DateTime.Now, "Poll Repeatedly until method is complete..");

            while (!asyncResult.IsCompleted)
            {
                TraceMsg(DateTime.Now, "Polling ….");

                Thread.Sleep(300);
            }

            DateTime completion = DateTime.MinValue;

            try
            {
                completion = longRunningMethod.EndInvoke(asyncResult);
            }
            catch
            {
            }

            TraceMsg(completion, "Polling example complete…");
        }

        public static void WaitingExample()
        {
            Console.WriteLine(Environment.NewLine + "*** Running Waiting Example ***");

            AsyncExampleDelegate longRunningMethod = LongRunningMethod;

            IAsyncResult asyncResult = longRunningMethod.BeginInvoke(2000, "Waiting", null, null);

            TraceMsg(DateTime.Now, "Waining until method is complete…");

            while (!asyncResult.AsyncWaitHandle.WaitOne(300, false))
            {
                TraceMsg(DateTime.Now, "Wait timeout….");
            }

            DateTime completion = DateTime.MinValue;

            try
            {
                completion = longRunningMethod.EndInvoke(asyncResult);
            }
            catch
            {
            }

            TraceMsg(completion, "Waiting example complete.");
        }

        public static void WaitAllExample()
        {
            Console.WriteLine(Environment.NewLine+ "*** Running WaitAll Example ***");

            ArrayList asyncResults = new ArrayList(3);

            AsyncExampleDelegate longRunningMethod = LongRunningMethod;

            asyncResults.Add(longRunningMethod.BeginInvoke(3000, "WaitAll 1", null, null));

            asyncResults.Add(longRunningMethod.BeginInvoke(2500, "WaitAll 2", null, null));

            asyncResults.Add(longRunningMethod.BeginInvoke(1500, "WaitAll 3", null, null));

            WaitHandle[] waitHandles = new WaitHandle[3];

            for (int count = 0; count < 3; count++)
            {
                waitHandles[count] = ((IAsyncResult)asyncResults[count]).AsyncWaitHandle;
            }

            TraceMsg(DateTime.Now, "Waiting until all 3 method are complete…");

            while(!WaitHandle.WaitAll(waitHandles, 300, false))
            {
                TraceMsg(DateTime.Now, "WaitAll timeout…");
            }

            DateTime completion = DateTime.MinValue;

            foreach(IAsyncResult result in asyncResults)
            {
                try{
                    DateTime time = longRunningMethod.EndInvoke(result);
                    if(time > completion) completion = time;
                }
                catch{
                }
            }
            TraceMsg(completion, "WaitAll example complete.");
        }

        public static void CallbackExample()
        {
            Console.WriteLine(Environment.NewLine + "*** Running Callback Example ***");

            AsyncExampleDelegate longRunningMethod = LongRunningMethod;

            IAsyncResult asyncResult = longRunningMethod.BeginInvoke(2000,
                "Callback", CallbackHandler, longRunningMethod);

            for (int count = 0; count < 15; count++)
            {
                TraceMsg(DateTime.Now, "Continue processing…");
                Thread.Sleep(200);
            }
        }

        public static void CallbackHandler(IAsyncResult result)
        {
            AsyncExampleDelegate longRunningMethod =
                (AsyncExampleDelegate)result.AsyncState;

            DateTime completion = DateTime.MinValue;

            try
            {
                completion = longRunningMethod.EndInvoke(result);
            }
            catch
            {
            }

            TraceMsg(completion, "Callback example complete.");
        }

        public static void Main()
        {
            BlockingExample();
            PollingExample();
            WaitingExample();
            WaitAllExample();
            CallbackExample();

            Console.WriteLine(Environment.NewLine);
            Console.WriteLine("Main method complete. Press Enter.");
            Console.ReadLine();
        }

    }
}

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s