Geeks With Blogs
Rahul Anand's Blog If my mind can conceive it, and my heart can believe it, I know I can achieve it.

By implementing multithreading in an application we can enable it to perform multiple operations simultaneously. Do remember that multithreading can not make a single processor to process two task in a single clock cycle, but the performance can be improved by utilizing the idle time of the processor. The other major benefit of multithreading in an application is, it drastically improves the response time.

 

Multithreading is not a suitable choice if the tasks at hand are dependent on each other. In this case multithreading will even slow down the processing, as it incurs a cost due to overheads involved with context switches.

 

Implementation of multithreading also adds a lot of complexity which needs to be addressed like deadlock handling, synchronized accesses, code complexity etc.

 

Hence implementing multithreading in an application should be a very thought of decision, so that the performance and response time can be improved.

 

At the design time we need to break down the whole program in smaller tasks which are independent of each other and can be performed simultaneously. These smaller tasks can be performed by different threads to improve performance.

 

Multithreading is almost unavoidable when we write a windows application which perform some real world tasks.

 

Windows Forms uses the single-threaded apartment (STA) model because Windows Forms is based on native Win32 windows that are inherently apartment-threaded. The STA model implies that a window can be created on any thread, but it cannot switch threads once created, and all function calls to it must occur on its creation thread. Outside Windows Forms, classes in the .NET Framework use the free threading model.

 

The STA model requires that any methods on a control that need to be called from outside the control's creation thread must be marshaled to (executed on) the control's creation thread. The base class Control provides several methods (Invoke, BeginInvoke, and EndInvoke) for this purpose. Invoke makes synchronous method calls; BeginInvoke makes asynchronous method calls.

 

When we run a Windows Application it always starts with a main thread that owns the form controls and it may be called the UI thread. Now suppose if we have some long running task execution involved on the click of a button, the UI will become irresponsive till it returns from the click handler method.

 

private void btnGetData_Click(object sender, System.EventArgs e)

{

// Long running task, simulated with a sleep of 1000 seconds

      Thread.Sleep(1000000);

}

 

The obvious solution is to make this long running task a separate method and call that method asynchronously from the click event handler.

 

private void MyLongRunningTask()

{

// Long running task, simulated with a sleep of 1000 seconds

      Thread.Sleep(1000000);

 

}

 

public delegate void LongTaskInvoker();

 

private void btnGetData_Click(object sender, System.EventArgs e)

{

      LongTaskInvoker myInvoker = new LongTaskInvoker(MyLongRunningTask);

/* No callback is required so first argument is null, no callback method is required hence no additional information is needed hence second argument is null */

myInvoker.BeginInvoke(null, null);

}

 

BeginInvoke() is a simple way to assign some work to a different thread. The .NET Framework allows you to call any method asynchronously by defining a delegate with the same signature as the method you want to call; the common language runtime automatically defines BeginInvoke and EndInvoke methods for this delegate, with the appropriate signatures.

The BeginInvoke method has the same parameters as the method you want to execute asynchronously, plus two additional parameters – a callback delegate and other information in an object (which will be available to callback method). BeginInvoke returns immediately and does not wait for the asynchronous call to complete. BeginInvoke returns an IasyncResult, which can be used to monitor the progress of the call.

Now this seems to work fine until we have a scenario where we want our asynchronous task to keep updating the UI about its processing. For instance suppose we have a long running task which calls a Web Service to get some data and then it do some calculations. The requirement is to keep the UI updated about the processing stage of this task, say we want to show messages like “Connecting to web service”, “Data returned by web service”, “Calculation stage 1”, “Calculation stage 2”,…..“finished processing”.

In an attempt to implement this requirement we will modify the MyLongRunningTask as follows:

  

private void MyLongRunningTask()

{

      // Long running task, simulated with a sleep of 1 second in a loop

      ShowWorkerMessage("Starting Long Running Task");

      for(int i = 0; i<1000; i++)

      {

            Thread.Sleep(1000);

            ShowWorkerMessage("Task Stage: "+ i.ToString());

      }

      ShowWorkerMessage("Completed Long Running Task");

}

 

public void ShowWorkerMessage(string message)

{

      lblMessage.Text = message;

}

 

Now here we are in trouble with this code – can you guess what? Yes it is a violation of statement – “The STA model requires that any methods on a control that need to be called from outside the control's creation thread must be marshaled to (executed on) the control's creation thread”. With BeginInvoke() call the MyLongRunningTask() executes on a different thread than UI thread. So it can not directly call ShowWorkerMessage() as it in turn updates the window form control (lblMessage). To solve this issue we modify the MyLongRunningTask() implementation as follows.

 

private void MyLongRunningTask()

{

// Long running task, simulated with a sleep of 1 second in a loop

      this.Invoke(ShowWorkerMessage,

            new object[]{"Starting Long Running Task"});

      for(int i = 0; i<1000; i++)

      {

            Thread.Sleep(1000);

            this.Invoke(ShowWorkerMessage,

                  new object[]{"Task Stage: "+ i.ToString()});

      }

      this.Invoke(ShowWorkerMessage,

            new object[]{"Completed Long Running Task"});

}

 

Since we have multiple call to ShowWorkerMessage() it would be better if we put the invocation related complexity in side the ShowWorkerMessage() method implementation. For this we modify the ShowWorkerMessage() as follows and revert the changes made in MyLongRunningTask() to previous version.

 

public void ShowWorkerMessage(string message)

{

if(lblMessage.InvokeRequired)

{

      this.Invoke(ShowWorkerMessage,

new object[]{message});

}

else

{

lblMessage.Text = message;

}

}

 

InvokeRequired  is a read only property defined under the base class ‘Control’, gets the value indicating whether the caller must call an invoke method when making method calls to that control because the caller is on a different thread than the one the control was created on.

 

In case the work to be done is complex in implementation, it is better to make a different class for worker thread which abstracts the implementation details of work to be processed.

 

public class WorkerThread

{

 

      private Thread _thread = null;                             

 

      public WorkerThread()

      {

            _thread = new Thread(new ThreadStart(Run));

            _thread.IsBackground = true;             

      }

 

      public void Start()

      {

            _thread.Start();

      }

 

      public Thread WorkerThread

      {

            get{ return _thread; }

      }

 

      private void Run()

      {

            // Implementation of work to be done                 

      }

}

 

private void btnGetData_Click(object sender, System.EventArgs e)

{

      WorkerThread myWorker = new WorkerThread();

myWorker.Start();

}

 

There are situations when the main UI thread wants to get some information about some critical event in the worker thread so that it can update some controls that it owns. Here we can use the framework’s delegate/event /handler architecture.

 

Suppose our worker thread raises an event when it has completed the work assigned, then the main thread can subscribe to it and display the completed message and enables the button for further processing.

 

We define a delegate for that purpose, and an event under the worker thread class:

 

public delegate void CompletedEventHandler(object sender, EventArgs e);

 

public event CompletedEventHandler WorkCompleted;

 

Following the design recommendations we implement a protected OnEvent method which actually raises the event.

 

protected void OnWorkCompleted(EventArgs e)

{

      if(WorkCompleted != null)

            WorkCompleted(this, e);

}

 

Now the main class can subscribe this event and do the necessary implementation in its event handler method.

 

private void btnGetData_Click(object sender, System.EventArgs e)

{

      WorkerThread myWorker = new WorkerThread();

myWorker.WorkCompleted +=

new CompletedEventHandler(mainThread_WorkCompleted);

myWorker.Start();

}

 

private void mainThread_WorkCompleted(object sender, EventArgs e)

{                

      stStatus.Text = "Done";

      btnStart.Enabled = true;

}

 

The delegate/event/handler architecture gives us another way to pass the message from worker thread to main thread so that it can update its controls.

 

I had taken reference lines from MSDN article where it was relevant to this article.

 

I would like to mention other useful links which talks about similar issues:

    http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnforms/html/winforms06112002.asp

    http://weblogs.asp.net/justin_rogers/articles/126345.aspx

 

Posted on Wednesday, March 22, 2006 7:45 AM C# , .NET Framework | Back to top


Comments on this post: Multithreaded Windows Applications

# re: Multithreaded Windows Applications
Requesting Gravatar...
Good tutorial,
Left by Rahul Gautam on Apr 26, 2006 9:28 AM

# re: Multithreaded Windows Applications
Requesting Gravatar...
Thanks so much for putting this together, I've been looking all over for a simple to follow introduction to threaded gui work. The fact that you included how to use a seperate threaded class makes this an all in one tutorial. Fantastic!
Left by Pleased on Dec 04, 2007 8:33 PM

# re: Multithreaded Windows Applications
Requesting Gravatar...
Thanks, helped me understand the EventHandler.
Left by Johan on Jun 11, 2009 3:11 AM

# re: Multithreaded Windows Applications
Requesting Gravatar...
Very good job and helped me a lot.
Left by G.Zhu on Dec 11, 2009 9:32 PM

Your comment:
 (will show your gravatar)


Copyright © Rahul Anand | Powered by: GeeksWithBlogs.net