Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

C# Threadding, one on one - an easy way to do multi-threadding

0.00/5 (No votes)
9 Jun 2007 1  
how to do threadding in .net with C# and update the UI from worker threads

Screenshot - threadding_test_screen01.jpg

Screenshot - threadding_test_screen02.jpg

Introduction

as you see in that screenshot i had 3 background threads , each doing some lenthy operation, but all 3 threads need to show their progress, so simply i will explain how to do that.

Background

I've been reading articles in the code project for a while (3 years actually) but i was struggling to find a good article about a tough subject which is threadding, and because i used to be a win32 developer back in the good old days, i know how painfull it is to do multi-threadding, also as a .net developer i know that the framework did an elegant job in makinf threadding easy, but not for beginners though, so i decided to put this article as a starting point for beginners to learn about threadding in .net, and specially about updating the UI (user interface) from another thread because it is the toughest thing to do for beginners.

Using the code

I've decided to make this as simple as i can, so the project is only a windows forms project developed in visual studio 2005 and contains only one form that shows the progress.

first thing i did was to drop the progress bars and buttons and of course i named them to make my life easier.

next i had to define a delegate for the worker thread that does some processing in the background, and it looks like this:

private delegate void DoOperationDelegate(int seconds, ProgressBar pBar, Button button);

the delegate takes 3 arguments:

  • int seconds: which is the number of milli seconds to delay the operation
  • ProgressBar pBar: the progress bar associated to show current operation's progress
  • Button button: the button to enable after the operation is finished

so we are cool now about the delegate, we needed the method that will do the actual work and looks like that delegate, and here it is:

 
private void DoOperation(int seconds, ProgressBar pBar, Button button)
{
    for (int i = 0; i <= 100; i++)
    {
        System.Threading.Thread.Sleep(seconds / 100);
        UpdateUI(button, pBar, i);
    }
}

it is very self-explaining, but lets talk about it for a little bit. as we can see the method has a for-loop from 0 to 100 which are value limits for the progress bar by default, so i am doing a 100 step operation and in each step i actually do nothing by Thread.Sleep(some time) and that some time is the total milleseconds given for the operation devided by 100 steps, but you can do actual lengthy work here and dont make the thread sleep.

after that sleep operation i call a very important method, which is the UpdateUI method, that actually shows the progress, also passing the progress bar and the button and the actual progress values

now lets examin the other part of the code which is the UpdateUI delegate

private

delegate void UpdateUIDelegate(Button button, ProgressBar pBar, int value);

that delegate does take three arguments:

  • Button button: the button to enable after the operation is finished
  • ProgressBar pBar: the progress bar associated to show current operation's progress
  • int value: the current value of operation progress (0 - 100)

and we implemented that delegate with the following code:

private void UpdateUI(Button button, ProgressBar pBar, int value)
{
    if (this.InvokeRequired)
    {
        UpdateUIDelegate d = UpdateUI;
        this.Invoke(d, new object[] {button, pBar, value });
        return;
    }

    
    if (value >= 100)
    {
        button.Enabled = true;
        pBar.Value = 100;
    }
    else
    {
        pBar.Value = value;
    }
}

as you can see , here is the actual thread Synchronization work, so in the first block of code , we checked the form property "InvokeRequired" to see if the method have been called from another thread or not, if this returns true, then we are running from another thread, so we need to tell the UI thread to do the work, not our current thread, and this is established by calling "this.Invoke" because the form (this) will run the delegated method on its thread and we passed the same parameters for the delegate in the same order we received them.

so when this happens the form's thread will execute our method, and when we check InvokeRequired we will find it = false and we continue updating our UI safely.

so far we are missing only one thing, the code to start the processing from a new thread

private void startButton1_Click(object sender, EventArgs e)
{
    startButton1.Enabled = false;
    DoOperationDelegate d = new DoOperationDelegate(DoOperation);
    d.BeginInvoke(1000, progressBar1, startButton1, null, null);
}

in that code you see the event handler for the button click for the first process, and actually the three event handler for the three buttons are all the same, except for the arguments that they pass to the delegate, and after creating a new instance from the delegate they call "BeginInvoke" which will start a new thread and executes the referenced method with the passed parameteres, but one thing for you fellas to know that there are two extra parameters for the BeginInvoke method, and i passed them as nulls because i didnt need them and they are out of our beginner scope actually.

Points of Interest

my interest with this article was to learn safe threadding with you, and i hope i did a good job, i will try to post other advanced examples, but i think this is enough so far, have fun guys and thanks for reading the article

History

June 09, 2007: First release.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here