Introduction

This article is for novice and amateur developers who recognize areas of their application that could use threading but don't want to be burdened with some of the complexity that comes with threading. Threading is a concept that many programmers tend to avoid because it can be difficult to understand, debug and implement. You can develop a very sophisticated multi-threaded application using C#. Don't worry, the BackgroundWorker object makes threading easy to use even if you don't want to take the time to understand everything about threading.

Using the Code

When your application loads, it runs on a single thread. This is referred to as the UI thread. Generally this is the thread that all of your UI objects have been created on and this is the thread that all of your code execution is performed on. The UI also uses this single thread to paint the UI objects. So when you're running a long task, like processing some unknown number of MP3 files in a directory, your application locks up, the window turns white, the user can't click any buttons, the title bar changes to "My Cool App (Not Responding)." So you go back and put in a bunch of Application.DoEvents() calls into your MP3 crunching function and all is better again… not really, the code runs slower now and the form still locks up but only for short spurts. The whole application seems a bit choppy.

What you need to do is this heavy processing on a different thread. Leave the UI thread free for painting the UI. .NET has made the BackgroundWorker object available to us to simplify threading. This object is designed to simply run a function on a different thread and then call an event on your UI thread when it's complete. The steps are simple, create a BackgroundWorker object, tell it what function to run on the background thread (the DoWork function), tell it what function to run on the UI thread when the work is complete (the RunWorkerCompleted function), then tell the BackgroundWorker object to go to work.

There is one rule you need to be aware of - you can't access UI objects on a thread that didn't create them. Therefore you would receive a runtime error if you wrote the line of code lblStatus.Text = "Processing file 5 of 100"; in the DoWork function. There are two ways around this and I use both in the examples. The BackgroundWorker object resolves this problem by giving us a ReportProgress function which can be called from the background thread's DoWork function, this will cause the ProgressChanged event to fire on the UI thread. Now we can access the UI objects on their thread and do what we want. But what if I just need to update a label or disable a button while on the background thread, no problem, using Control.Invoke you can supply some code (in an anonymous function) to be run on the UI thread, I use this technique in the asynchronous example to update the Progress Form's label and progress bar.

Synchronous Example

There are two examples in this article, one on synchronous threading and the other on asynchronous threading. The idea behind the synchronous example is that you want to disable your application so the user can't do anything else, but you want the application to still paint while you notify the user of the progress and give him or her the ability to cancel the process.

publicpartialclass fmMain : Form
{
// The progress form will be created and shown modally while the
// synchronous process is running. This form will notify the background
// thread if a cancellation is performed. The background thread
// will update the status label and ProgressBar
// on the Progress Form using Control.Invoke.
private fmProgress m_fmProgress = null;
#region Synchronous BackgroundWorker Thread
privatevoid bnSync_Click( object sender, EventArgs e )
{
// Create a background thread
BackgroundWorker bw = new BackgroundWorker();
bw.DoWork += new DoWorkEventHandler( bw_DoWork );
bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler
( bw_RunWorkerCompleted );
// Create a progress form on the UI thread
m_fmProgress = new fmProgress();
// Kick off the Async thread
bw.RunWorkerAsync();
// Lock up the UI with this modal progress form.
m_fmProgress.ShowDialog( this );
m_fmProgress = null;
}
privatevoid bw_DoWork( object sender, DoWorkEventArgs e )
{
// Do some long running task...
int iCount = new Random().Next( 20, 50 );
for( int i = 0; i < iCount; i++ )
{
// The Work to be performed...
Thread.Sleep( 100 );
// Update the description and progress on the modal form
// using Control.Invoke. Invoke will run the anonymous
// function to set the label's text on the UI thread.
// Since it's illegal to touch the UI control on the worker
// thread that we're on right now.
// Moron Anonymous functions:
// http://www.codeproject.com/books/cs2_anonymous_method.asp
m_fmProgress.lblDescription.Invoke((MethodInvoker) delegate()
{
m_fmProgress.lblDescription.Text =
"Processing file " + i.ToString() +
" of " + iCount.ToString();
m_fmProgress.progressBar1.Value =
Convert.ToInt32( i * ( 100.0 / iCount ) );
});
// Periodically check for a cancellation
// If the user clicks the cancel button, or tries to close
// the progress form, the m_fmProgress.Cancel flag
// will be set to true.
if( m_fmProgress.Cancel )
{
// Set the e.Cancel flag so that the WorkerCompleted event
// knows that the process was cancelled.
e.Cancel = true;
return;
}
}
}
privatevoid bw_RunWorkerCompleted
( object sender, RunWorkerCompletedEventArgs e )
{
// The background process is complete. First we should hide the
// modal Progress Form to unlock the UI. Then we need to inspect our
// response to see if an error occurred, a cancel was requested or
// if we completed successfully.
// Hide the Progress Form
if( m_fmProgress != null )
{
m_fmProgress.Hide();
m_fmProgress = null;
}
// Check to see if an error occurred in the
// background process.
if( e.Error != null )
{
MessageBox.Show( e.Error.Message );
return;
}
// Check to see if the background process was cancelled.
if( e.Cancelled )
{
MessageBox.Show( "Processing cancelled." );
return;
}
// Everything completed normally.
// process the response using e.Result
MessageBox.Show( "Processing is complete." );
}
#endregion
}

Asynchronous Example

The purpose of the asynchronous example is to allow the user to kick off a process while still having the ability to continue using your application. However, the user still needs to have the ability to determine the progress of the process and the ability to cancel it. In this example we don't want to display modal for that which disables the application.

publicpartialclass fmMain : Form
{
// The BackgroundWorker will be used to perform a long running action
// on a background thread. This allows the UI to be free for painting
// as well as other actions the user may want to perform. The background
// thread will use the ReportProgress event to update the ProgressBar
// on the UI thread.
private BackgroundWorker m_AsyncWorker = new BackgroundWorker();
public fmMain()
{
InitializeComponent();
// Create a background worker thread that ReportsProgress &
// SupportsCancellation
// Hook up the appropriate events.
m_AsyncWorker.WorkerReportsProgress = true;
m_AsyncWorker.WorkerSupportsCancellation = true;
m_AsyncWorker.ProgressChanged += new ProgressChangedEventHandler
( bwAsync_ProgressChanged );
m_AsyncWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler
( bwAsync_RunWorkerCompleted );
m_AsyncWorker.DoWork += new DoWorkEventHandler( bwAsync_DoWork );
}
#region Asynchronous BackgroundWorker Thread
privatevoid bnAsync_Click( object sender, EventArgs e )
{
// If the background thread is running then clicking this
// button causes a cancel, otherwise clicking this button
// launches the background thread.
if( m_AsyncWorker.IsBusy )
{
bnAsync.Enabled = false;
lblStatus.Text = "Cancelling...";
// Notify the worker thread that a cancel has been requested.
// The cancel will not actually happen until the thread in the
// DoWork checks the bwAsync.CancellationPending flag, for this
// reason we set the label to "Cancelling...", because we haven't
// actually cancelled yet.
m_AsyncWorker.CancelAsync();
}
else
{
bnAsync.Text = "Cancel";
lblStatus.Text = "Running...";
// Kickoff the worker thread to begin it's DoWork function.
m_AsyncWorker.RunWorkerAsync();
}
}
privatevoid bwAsync_DoWork( object sender, DoWorkEventArgs e )
{
// The sender is the BackgroundWorker object we need it to
// report progress and check for cancellation.
BackgroundWorker bwAsync = sender as BackgroundWorker;
// Do some long running operation here
int iCount = new Random().Next( 20, 50 );
for( int i = 0; i < iCount; i++ )
{
// Working...
Thread.Sleep( 100 );
// Periodically report progress to the main thread so that it can
// update the UI. In most cases you'll just need to send an
// integer that will update a ProgressBar,
// but there is an OverLoad for the ReportProgress function
// so that you can supply some other information
// as well, perhaps a status label?
bwAsync.ReportProgress( Convert.ToInt32( i * ( 100.0 / iCount )));
// Periodically check if a cancellation request is pending.
// If the user clicks cancel the line
// m_AsyncWorker.CancelAsync(); if ran above. This
// sets the CancellationPending to true.
// You must check this flag in here and react to it.
// We react to it by setting e.Cancel to true and leaving.
if( bwAsync.CancellationPending )
{
// Pause for a bit to demonstrate that there is time between
// "Cancelling..." and "Cancel ed".
Thread.Sleep( 1200 );
// Set the e.Cancel flag so that the WorkerCompleted event
// knows that the process was cancelled.
e.Cancel = true;
return;
}
}
bwAsync.ReportProgress( 100 );
}
privatevoid bwAsync_RunWorkerCompleted
( object sender, RunWorkerCompletedEventArgs e )
{
// The background process is complete. We need to inspect
// our response to see if an error occurred, a cancel was
// requested or if we completed successfully.
bnAsync.Text = "Start Long Running Asynchronous Process";
bnAsync.Enabled = true;
// Check to see if an error occurred in the
// background process.
if( e.Error != null )
{
MessageBox.Show( e.Error.Message );
return;
}
// Check to see if the background process was cancelled.
if( e.Cancelled )
{
lblStatus.Text = "Cancelled...";
}
else
{
// Everything completed normally.
// process the response using e.Result
lblStatus.Text = "Completed...";
}
}
privatevoid bwAsync_ProgressChanged
( object sender, ProgressChangedEventArgs e )
{
// This function fires on the UI thread so it's safe to edit
// the UI control directly, no funny business with Control.Invoke.
// Update the progressBar with the integer supplied to us from the
// ReportProgress() function. Note, e.UserState is a "tag" property
// that can be used to send other information from the
// BackgroundThread to the UI thread.
progressBar1.Value = e.ProgressPercentage;
}
#endregion
}

If I want to add a checkbox, such as "Loop Run", in the form, if it was checked, it will run the background thread all the time, until the "Cancel" button is checked; otherwise, the background thread just run only one time.

Ported code to VB.NET 3.5 and works well...
Getting AccessViolationException from time to time for .NET 2.0/3.5 and application crashes
I've checked the code a lot of times, but I don't see a solution,. Please help!

I feel like I am missing something when it comes to cancelling the background thread.
I have a situation where i send the background worker off to do some work and it may be gone a while depending on the parameters used. Let's say that I am going after a large amount of data from our ERP system. In this case I can't periodically check CancelationPending (or can I?).
Assuming the dowork is off doing its job for a very long time, how do you cancel the thread?

Thank you for you effort to post a nice article here.
I have an annoying problem with closing my application.
I use the background worker to grab GPS data from bluetooth, and I use also a timer which starts the asycnhronous DoWork method every period.

In the DoWork method there is a loop which stops looping until it gets a fixed position (which means a valid position), if not it keeps looping until it has a fix. Ofcourse during looping I switch the timer off, so I don't run into troubles. But when I close the application I call also the CancelAsync(), so to cancel the backgroundworker, but than I get an exception about a thread is still running.

Do you know how I can close the backgroundworker and the serial port on gentle way, while DoWork is looping?

I have the same problem, well have you find the soluction? i have see other example that using a com port with backgroundworker but i don't note any different with my code. I call a cancelasync() and after i close the comport, and so i have an exception that is intercepted from system operator "YUO ARE EXIT FROM THREAD ..."

Hi, I'm trying to use your ASYNC example to suit my needs but i'm kind of lost with one issue: everytime the form losses focus, the background process remains 'inactive'. To re-activate it I have to, for example press a different button on the form. What am I missing??

Being a novice programmer, I've spent over 30 hours spinning my wheels, trying to figure out why everything was breaking in random and unpredictable places ... and I knew it had to do with my background workers.

Having read this, I now realized my HUGE mistake, I wanted SYNCHRONOUS workers, not async. Thank you soooo much!

Just one question, I'm hoping you could help with. I have a process that queries a database. When there are no results, my background worker returns completed faster than the progress dialog can open. Which then causes an exception to be thrown. The only work around I can think of is if there are no results, spin around in a while loop for a little bit and then finish up. I have a sneaking suspicion this isn't the cleanest way to do things though. Any suggestions?

If you want your UI to be responsive while the background thread is working rather than sleeping, you need to make sure to spare some CPU time for the UI thread. Either you place Sleep() calls in your working thread or you lower its thread priority.
Threads within one process do cooperative multitasking - between processes we have preemptive multitasking.

Umm nope thats not right at all. All threads on the system will be run by the scheduler, regardless of what process they are in.
Having said that its not a bad idea to lower the priority of your background thread, it will make the UI more responsive. You don't need to call sleep at all though.

Thank you for all of your positive feedback, it's going straight to my head. Hopefully I'll have my next article out by the end of the week I think the title's going to be Delegates for Dummies. Delegates seem to trip up so many developers it's worth dumbing down to a simple explanation.

Hi Andrew,
Yes, please do a "Delagates for Dummies" article. No matter how many tutorials and article I've read on the subject, it just hasn't sunk in and I'm still a dummy when it comes to Delagates. Your Thread article was very helpful. Thanks

Certainly using an event to communicate between the progress form and the worker thread would be legitimate and possibly better solution. In the 2nd example I use the BackgroundWorker's ReportProgress method to raise the OnProgress event. I chose not to go this route in the first example to demonstrate how to talk to UI objects "directly" (using Invoke) from the worker thread. Thanks for your feedback