I have a stylistic question about the choice of background thread implementation I should use on a windows form app. Currently I have a BackgroundWorker
on a form that has an infinite (while(true))
loop. In this loop I use WaitHandle.WaitAny
to keep the thread snoozing until something of interest happens. One of the event handles I wait on is a "StopThread
" event so that I can break out of the loop. This event is signaled when from my overridden Form.Dispose()
.
I read somewhere that BackgroundWorker
is really intended for operations that you don't want to tie up the UI with and have an finite end - like downloading a file, or processing a sequence of items. In this case the "end" is unknown and only when the window is closed. Therefore would it be more appropriate for me to use a background Thread instead of BackgroundWorker
for this purpose?
This question is related to
.net
winforms
multithreading
backgroundworker
Some of my thoughts...
I knew how to use threads before I knew .NET, so it took some getting used to when I began using BackgroundWorker
s. Matt Davis has summarized the difference with great excellence, but I would add that it's more difficult to comprehend exactly what the code is doing, and this can make debugging harder. It's easier to think about creating and shutting down threads, IMO, than it is to think about giving work to a pool of threads.
I still can't comment other people's posts, so forgive my momentary lameness in using an answer to address piers7
Don't use Thread.Abort();
instead, signal an event and design your thread to end gracefully when signaled. Thread.Abort()
raises a ThreadAbortException
at an arbitrary point in the thread's execution, which can do all kinds of unhappy things like orphan Monitors, corrupt shared state, and so on.
http://msdn.microsoft.com/en-us/library/system.threading.thread.abort.aspx
I want to point out one behavior of BackgroundWorker class that wasn't mentioned yet. You can make a normal Thread to run in background by setting the Thread.IsBackground property.
Background threads are identical to foreground threads, except that background threads do not prevent a process from terminating. [1]
You can test this behavoir by calling the following method in the constructor of your form window.
void TestBackgroundThread()
{
var thread = new Thread((ThreadStart)delegate()
{
long count = 0;
while (true)
{
count++;
Debug.WriteLine("Thread loop count: " + count);
}
});
// Choose one option:
thread.IsBackground = true; // <--- This will make the thread run in background
thread.IsBackground = false; // <--- This will delay program termination
thread.Start();
}
When the IsBackground property is set to true and you close the window, then your application will terminate normaly.
But when the IsBackground property is set to false (by default) and you close the window, then just the window will disapear but the process will still keep running.
The BackgroundWorker class utilize a Thread that runs in the background.
What's perplexing to me is that the visual studio designer only allows you to use BackgroundWorkers and Timers that don't actually work with the service project.
It gives you neat drag and drop controls onto your service but... don't even try deploying it. Won't work.
Services: Only use System.Timers.Timer System.Windows.Forms.Timer won't work even though it's available in the toolbox
Services: BackgroundWorkers will not work when it's running as a service Use System.Threading.ThreadPools instead or Async calls
Also you are tying up a threadpool thread for the lifetime of the background worker, which may be of concern as there are only a finite number of them. I would say that if you are only ever creating the thread once for your app (and not using any of the features of background worker) then use a thread, rather than a backgroundworker/threadpool thread.
The basic difference is, like you stated, generating GUI events from the BackgroundWorker
. If the thread does not need to update the display or generate events for the main GUI thread, then it can be a simple thread.
Pretty much what Matt Davis said, with the following additional points:
For me the main differentiator with BackgroundWorker
is the automatic marshalling of the completed event via the SynchronizationContext
. In a UI context this means the completed event fires on the UI thread, and so can be used to update UI. This is a major differentiator if you are using the BackgroundWorker
in a UI context.
Tasks executed via the ThreadPool
cannot be easily cancelled (this includes ThreadPool
. QueueUserWorkItem
and delegates execute asyncronously). So whilst it avoids the overhead of thread spinup, if you need cancellation either use a BackgroundWorker
or (more likely outside of the UI) spin up a thread and keep a reference to it so you can call Abort()
.
You know, sometimes it's just easier to work with a BackgroundWorker regardless of if you're using Windows Forms, WPF or whatever technology. The neat part about these guys is you get threading without having to worry too much about where you're thread is executing, which is great for simple tasks.
Before using a BackgroundWorker
consider first if you wish to cancel a thread (closing app, user cancellation) then you need to decide if your thread should check for cancellations or if it should be thrust upon the execution itself.
BackgroundWorker.CancelAsync()
will set CancellationPending
to true
but won't do anything more, it's then the threads responsibility to continually check this, keep in mind also that you could end up with a race condition in this approach where your user cancelled, but the thread completed prior to testing for CancellationPending
.
Thread.Abort()
on the other hand will throw an exception within the thread execution which enforces cancellation of that thread, you must be careful about what might be dangerous if this exception was suddenly raised within the execution though.
Threading needs very careful consideration no matter what the task, for some further reading:
Parallel Programming in the .NET Framework Managed Threading Best Practices
If it ain't broke - fix it till it is...just kidding :)
But seriously BackgroundWorker is probably very similar to what you already have, had you started with it from the beginning maybe you would have saved some time - but at this point I don't see the need. Unless something isn't working, or you think your current code is hard to understand, then I would stick with what you have.
A background worker is a class that works in a separate thread, but it provides additional functionality that you don't get with a simple Thread (like task progress report handling).
If you don't need the additional features given by a background worker - and it seems you don't - then a Thread would be more appropriate.
Source: Stackoverflow.com