Thread vs BackgroundWorker

Background

There are two classes available in the .NET framework that sometimes have some confusion around them: The Thread and the BackgroundWorker. They’re both used to do some heavy lifting for you on a separate thread of execution (so you can keep on keepin’ on), so why do we have two different things to accomplish the same end result

 

Enter The Thread Class

The Thread class is available in the System.Threading namespace. Surprising, right? It’s the basic unit for spawning off work to be done. Threads let you provide them with a name, which could be one advantage to using them. A thread can either operate as “background” which means it will be killed when the application exists, or not as background, which will actually keep the application alive until the thread is killed off.

An instance of the Thread class is relatively lightweight. It’s quick to set up for developers and all you need to do is provide it a method to run. You can put a loop in your thread body to keep it alive and do all sorts of fun stuff. Threads are great for setting up queuing, dequeing, scheduling, monitoring, receiving, and listening logic. Well, there are really countless uses for them, but those are some of the big ones I find I do a lot of.

 

Enter The BackgroundWorker

The BackgroundWorker class is available in the System.ComponentModel namespace. This is slightly different from the Thread class already, and for what it’s worth, I generally only have this namespace around if I’m dealing with a UI. That is, if I’m in the equivalent to a data layer or application layer, I usually don’t have these guys around (usually, but not necessarily always). So is that it then? Just the namespace is different?

The BackgroundWorker class is essentially built on top of the Thread class. The Thread part of the BackgroundWorker is sort of hidden from you. You get to work with two very important parts of the BackgroundWorker though, the DoWork and RunWorkerCompleted events (There’s a progress one too, but because I actually don’t use this much I’ll omit it for you to take on as homework). So… What are these events all about?

The DoWork event is invoked on a separate thread. This is where you want to do your heavy lifting, and you can pass in any object you want when you start up the BackgroundWorker–Simply pull it off of the event args in your DoWork event handler and cast it back to the necessary type. Presto! The RunWorkerCompleted event is what’s triggered when your DoWork event handler finishes up… but the big difference here is that RunWorkerCompleted runs on the thread that started the BackgroundWorker. This is extremely important when you’re working with UIs. Why? Because of cross thread exceptions! UI stuff is generally only run on the UI thread and nothing else. It’s important to note that the DoWork event handler can pass more state to the RunWorkerCompleted event handler by setting a result property on the event args. The RunWorkerCompleted event handler can then take advantage of this data!

My Guidelines

In the end, both of these classes can be used to do work on a different thread than the one you’re currently on. That’s great news. So what are my guidelines for picking one over the other?

  • If you have a long running task that persists, or perhaps something that is running that conceivable have stop/running/paused states (regardless of whether or not you implemented them) you may want a Thread.
  • If you have a task you want to run with the result handled and cleaned up afterward (i.e. a clear distinction between go do this stuff and let me handle the result) then you may want a background worker.
  • If you have a task to be done that you don’t want to block the UI but want to show the result afterward (i.e. loading tons of data to put in a list) then you probably want a background worker.

 

Summary

Threads and background workers can often be used to accomplish the same thing: offloading work to be done on a different thread of execution. I’ve tried to provide my own personal guidelines for when to use either, but there is no law to stop you from doing it as you see fit. As long as you understand what either option provides you, you can make your own decision based on your needs.

author avatar
Nick Cosentino Principal Software Engineering Manager
Principal Software Engineering Manager at Microsoft. Views are my own.

Leave a Reply