Infosys Microsoft Alliance and Solutions blog

« BizTalk 2006 Documentation | Main | Troubleshooting BizTalk Applications »

Asynchronous Programming Model in .NET Framework 2.0 - Part II,,,

Let us continue from where we left off in “Asynchronous Programming Model in .NET Framework 2.0 – Part I”. But, in this blog, instead of delving deep into EBAPM implementation details, I will step into various ways to achieve asynchronous invocation of method calls, in .NET Framework 2.0. That will give us better perspective of Asynchronous programming model. Asynchronous programming model can be simplistically defined as invoking methods in separate threads from main UI or primary threads.

 

.NET, being a rich framework, it provides more than one option to achieve it. In fact, a few options that we may be familiar with, even without knowing that they invoke methods in different threads than the main ones.

 

Asynchronous invocation is possible through the following approaches, apart from the ones that we have seen in my previous blog,

  1. through QueueUserWorkItem method of ThreadPool class
  2. through an explicitly created thread
  3. through Timer class
  4. through BackgroundWorker class

Out of these, BackgroundWorker class is new to .NET Framework and it has been introduced in .NET Framework 2.0. While the approaches are more or less the same in invocation part, new asynchronous features in .NET Framework 2.0 such as EBAPM, BackgroundWorker class provide more flexibility in terms of canceling the ongoing asynchronous operations and getting the incremental status of background running operations so that progress bar updates is possible at UI side.

I have created code snippets for all these approaches in the following windows form application that will have the UI as given below.

Asynchronous Invocations in .NET Fwk 2.0 

And I have invoked the following very primitive Web Service in that windows Form application.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Threading;
namespace BackgroundWorkerWinApp
{
    public partial class Form1 : Form
    {
        BackgroundWorker bgw;
        BackgroundWorkerWinAppWS.BackgroundWorkerWinAppWS proxy;
       
        public Form1()
        {
            InitializeComponent();
            proxy = new BackgroundWorkerWinAppWS.BackgroundWorkerWinAppWS();
            #region Asynchrouns invocation through WS Proxy - event binding
            proxy.HelloWorldCompleted += delegate(object sender, BackgroundWorkerWinAppWS.HelloWorldCompletedEventArgs e)
            {
                textBoxStatus.Text = e.Result.ToString();
                textBoxStatus.BackColor = Color.Gray;
            };
            #endregion
            #region Asynchronous invocation through BackgroundWorker - event binding
            bgw = new BackgroundWorker();
            bgw.DoWork += delegate(object sender, DoWorkEventArgs e)
            {
                textBoxStatus.Text = proxy.HelloWorld();
                textBoxStatus.BackColor = Color.Green;
            };
            #endregion
        }
        #region Synchronous invocation of Web Service
        private void btnInvokeWebService_Click(object sender, EventArgs e)
        {
            textBoxStatus.Text = proxy.HelloWorld();
            textBoxStatus.BackColor = Color.Blue;
        }
        #endregion
        #region Asynchronous invocation through BackgroundWorker class
        private void btnInvokeWebServiceThroughBGW_Click(object sender, EventArgs e)
        {
           bgw.RunWorkerAsync();
        }
        #endregion
        #region Asynchronous invocation through Web Service proxy
        private void btnInvokeWSAsyncThroughWSProxy_Click(object sender, EventArgs e)
        {
            proxy.HelloWorldAsync();
        }
        #endregion
       
        #region Asynchronous Invocation through QueueUserWorkItem
        private void QueueUserWorkItemWSInvocation(object state)
        {
            textBoxStatus.Text = proxy.HelloWorld();
            textBoxStatus.BackColor = Color.GreenYellow;
        }
        private void btnInvokeWSAsyncThroughQueueUserWorkitem_Click(object sender, EventArgs e)
        {
            ThreadPool.QueueUserWorkItem(new WaitCallback(QueueUserWorkItemWSInvocation));
        }
        #endregion
        #region Asynchronous invocation through custom thread
        private void ThreadStartWSInvocation()
        {
            textBoxStatus.Text = proxy.HelloWorld();
            textBoxStatus.BackColor = Color.Honeydew;
        }
       
        private void btnInvokeWSAsyncThroughCustomThread_Click(object sender, EventArgs e)
        {
            ThreadStart threadStart = new ThreadStart(ThreadStartWSInvocation);
            Thread thread = new Thread(threadStart);
            //Thread, by default, behaves like a foreground thread
            //thread.IsBackground = true;
            thread.Start();
        }
        #endregion
        #region Asynchronous invocation through Timer
        private void TimerBasedWSInvocation(object state)
        {
            textBoxStatus.Text = proxy.HelloWorld();
            textBoxStatus.BackColor = Color.Indigo;
        }
        private void btnInvokeWSAsyncThroughTimer_Click(object sender, EventArgs e)
        {
            System.Threading.Timer timer = new System.Threading.Timer(new TimerCallback(TimerBasedWSInvocation));
            timer.Change(0, Timeout.Infinite);
        }
        #endregion
    }
}
 

Now, Let us go through the details of each approach.

Asynchronous invocation through QueueUserWorkItem.

The primary reason to use QueueUserWorkItem method of ThreadPool class is to invoke a method asynchronously using an available thread from CLR thread pool. In .NET Fwk 1.x, it is the recommended one for invoking an operation asynchronously. The following code snippet shows how to use QueueUserWorkItem method.

ThreadPool.QueueUserWorkItem(new WaitCallback(QueueUserWorkItemWSInvocation));

And WaitCallback delegate in our code, given below, invokes the web service synchronously.

private void QueueUserWorkItemWSInvocation(object state)
{
      textBoxStatus.Text = proxy.HelloWorld();
}
 

Asynchronous invocation through an explicit thread.

Though the usage of QueueUserWorkItem is highly preferred, we still need to invoke operations by a thread that is created explicitly by us, when we need to have some control on the thread that executes the operation. For instance, when we use a thread pool thread, we have no control over the type of thread (whether it is a foreground or background thread), priority of thread and apartment state of the thread (by default, CLR threads are set to MTA). And another important reason to go for explicit thread creation is that we may not want to tie up a thread from common thread pool for a very long running operation, because threadpool will be shared across applications. When we need to exert control on any of the above mentiones ones, we have to resort to creating an explicit thread.

The following is the delegate that is required to be passed as a parameter into ThreadStart class which is required to create a thread.

private void ThreadStartWSInvocation()
{
        textBoxStatus.Text = proxy.HelloWorld();
}
    
  
private void btnInvokeWSAsyncThroughCustomThread_Click(object sender, EventArgs e)
{
         ThreadStart threadStart = new ThreadStart(ThreadStartWSInvocation);
         Thread thread = new Thread(threadStart);           
         thread.Start();
}

Asynchronous invocation through Timer.

There is another way to invoke an operation in a separate thread, is by using a timer class. You might know that there are timer classes in three different namespaces.    

  1. Timer class in System.Threading namespace
  2. Timer class in System.Windows.Forms namespace
  3. Timer class in System.Timers namespace

Essentially, a timer is to execute an operation periodically in background using a separate thread. The purpose of existence of each one of them is distinct. The best explanation that I have read for each of them is from “CLR via C# - Applied Microsoft .NET Framework Programming” by Jeffrey Richter. According to that book, System.Windows.Forms.Timer associates the timer with the calling thread, and thus ensures that an operation is invoked through that timer in the same thread (main UI thread) that created the timer. System.Timers.Timer is a wrapper over System.Threading.Timer and this timer is specially designed to be used in design surface of windows form applications. And out of these three, System.Threading.Timer is the recommended one to invoke an operation in background periodically. So, I have used System.Threading.Timer in my code snippet as given below.

The following delegate invokes web service in synchronous manner.

private void TimerBasedWSInvocation(object state)
{
        textBoxStatus.Text = proxy.HelloWorld();
}

The following method shows how to use the timer to invoke the above delegate.

It is to be noted that first parameter of change() method is to denote how soon, from the time of invocation of timer, the method needs to be executed (here, 0 means immediately) and second parameter is to denote, how frequently the operation needs to be executed repeatedly (Timeout.Infinite means the operation is to be executed only once).

private void btnInvokeWSAsyncThroughTimer_Click(object sender, EventArgs e)
{
        System.Threading.Timer timer = new System.Threading.Timer(new TimerCallback(TimerBasedWSInvocation));
        timer.Change(0, Timeout.Infinite);
}

Asynchronous invocation through BackgroundWorker class.

BackgroundWorker class is introduced in .NET Framework 2.0, mainly, to invoke long running operations in Windows form applications, without worrying about using a delegate in callback method (to switch over to main UI thread from worker thread, as happened in Begin/End<Method> approach) in order to update the UI controls. As I had mentioned earlier, it is more flexible and powerful than .NET Fwk 1.x approaches, as it supports canceling as well as retrieving the incremental status about the ongoing asynchronous operations. To make the examples simple, I have not coded for those features here.

The BackgroundWorker class is instantiated and a delegate that is going to call web service synchronously is linked to a predefined event “DoWork” of BackgroundWorker object. The code snippet is given below.

BackgroundWorker bgw = new BackgroundWorker();
bgw.DoWork += delegate(object sender, DoWorkEventArgs e)
{
      textBoxStatus.Text = proxy.HelloWorld();              
};

private void btnInvokeWebServiceThroughBGW_Click(object sender, EventArgs e)
{
      bgw.RunWorkerAsync();
}

Having seen those different approaches to call an operation asynchronously, let us move to the implementation details of EBAPM in my next blog. But, an interesting thing that we have to understand with related to the type of thread (foreground or background) is the process will be terminated only after the completion of execution of all foreground threads in it. For example, when we create an explicit thread, it will be created as a foreground thread by default. It means, process will not be torn down till the operation executed by this thread is completed. But an explicitly created thread can be set to be a background thread, by setting that thread’s property - IsBackground to true. I tested this code to know how threads in other approaches behave with respect to the termination of application. What I did was, I executed this windows form application along with Windows Task Manager. I clicked on either one of the buttons in the UI and immediately close down the application. Then I checked how long it takes for the application instance to disappear in the windows task manager. What I have noticed is only explicitly created thread is a foreground thread and all other approaches utilize background threads. Then I set the explicitly created thread to be background thread by setting IsBackground to true and repeated the experiment. Yes, now process got terminated immediately once I shut down the application.

 

 

Comments

It would be great if we can discuss Mutexes and Semaphores(available only in .NET 2.0) which are also recommended approaches for asynchronous communication.

Mutex and Semaphore are mechanisms to enforce synchronizing the access of threads to a shared resource. They are essential for not leaving the shared resource in an improper state, when more than one thread are involving in an application. As i did not use a complex scenario which would entitle such mechanisms, i did not mention about them. Semaphore, is in fact a newly introduced class in .NET Fwk 2.0, that restricts only a specific number of threads to access a shared resource, concurrently.

Post a comment

(If you haven't left a comment here before, you may need to be approved by the site owner before your comment will appear. Until then, it won't appear on the entry. Thanks for waiting.)

Please key in the two words you see in the box to validate your identity as an authentic user and reduce spam.

Subscribe to this blog's feed

Follow us on

Blogger Profiles

Infosys on Twitter