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?
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
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.
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.
You can test this behavoir by calling the following method in the constructor of your form window.
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.
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 theSynchronizationContext
. 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 theBackgroundWorker
in a UI context.Tasks executed via the
ThreadPool
cannot be easily cancelled (this includesThreadPool
.QueueUserWorkItem
and delegates execute asyncronously). So whilst it avoids the overhead of thread spinup, if you need cancellation either use aBackgroundWorker
or (more likely outside of the UI) spin up a thread and keep a reference to it so you can callAbort()
.I knew how to use threads before I knew .NET, so it took some getting used to when I began using BackgroundWorkers. 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