Saturday 21 April 2012

Asynchronous method in C# - Part I


Introduction
In this article, we’ll demonstrate how to write asynchronous method. For better understanding first we’ll perform task conventionally and after that we’ll create its Async version.
Objective
To write Asynchronous method.
Using the code
Let first design class say Task and write a Perform() method that iterate loops over some collection.
    class Task
    {
        private void Perform(string[] files)
        {
            foreach (string file in files)
            {
                //do something......
                Thread.Sleep(100);
            }
        }
    }
See above example in which we are iterating loop for array of string. This is convention method which we all normaly write.
Now, let’s try to perform same task asynchronously using delegates. For this we need following member:
  • Perform() method – does actual work.
  • PerformAsync() method – invokes the asynchronous operation.
  • IsBusy property – indicates that asynchronous operation is going on.
  • CompleteTask() method – called when perform method completed operation.
  • TaskCompleted event – notifies of the asynchronous operation completion.

Perform() Method:
This method executes in background and does actual task. In our example it iterates loop over array of string.
        private void Perform(string[] files)
        {
            foreach (string file in files)
            {
                //do something......
                Thread.Sleep(100);
            }
        }

        delegate void TaskEventHandler(string[] files, AsyncOperation async, SendOrPostCallback callback);

PerformAsync() Method:

This method invokes asynchronous operation and returns immediately. If asynchronous operation is running then throw an exception.

        public void PerformAsync(string[] files)
        {
            if (IsBusy)
                throw new InvalidOperationException("The background worker is busy.");

            async = AsyncOperationManager.CreateOperation(this);

            TaskEventHandler handler =
                new TaskEventHandler(ProcessWorker);
            handler.BeginInvoke(files, async, CompleteWorker, null, null);
        }

First it checks for busy status of operation, if it’s so then throw InvalidCastOperationException.
Next an AsyncOperation is created. This object is used by worker thread to invoke client’s event handler on proper thread.
Next TaskEventHandler is registered with proper handler method. Through TaskEventHandler, we can invoke our Task asynchronously.
Now, the asynchronous operation is started in separate thread using handler.BeginInvoker method. BeginInvoke method contains two more parameter along with string array.
  1. A delegate of type SendOrPostCallback to a callback method which called when operation finishes.
  2. A custom object that is stored in the AsyncState property of  an IAsyncResult instance return by BeginInvoke method.

CompleteTask Method:

This method calls when worker invoker has finishes it’s processes.
        void CompleteTask(object state)
        {
            object[] args = (object[])state;
            RunWorkerCompletedEventArgs e =
                args[0] as RunWorkerCompletedEventArgs;
            AsyncOperation async = args[1] as AsyncOperation;

            SendOrPostCallback callback = delegate(object darg)
            {
                OnRunWorkerCompleted(darg as RunWorkerCompletedEventArgs);
            };

            async.PostOperationCompleted(callback, e);

            this.async = null;
        }

First the AsyncOperation object is obtained and at last TaskCompleted event fired through AsyncOperation object

TaskCompleted Event:
This event fired when the asynchronous operation completed.

        public event RunWorkerCompletedEventHandler TaskCompleted
        {
            add
            {
                this.taskCompletedEventHandler += value;
            }
            remove
            {
                this.taskCompletedEventHandler -= value;
            }
        }
        private RunWorkerCompletedEventHandler taskCompletedEventHandler;

        protected virtual void OnTaskCompleted(RunWorkerCompletedEventArgs e)
        {
            if (taskCompletedEventHandler != null)
                taskCompletedEventHandler(this, e);
        }

In this Series
  1. Asynchronous method in C# - Part I
  2. Asynchronous method in C# - Part II

No comments:

Post a Comment