04 March, 2011

Threading: BackgroundWorker vs. ThreadPool ?

From time to time you find yourself (if you are a serious developer;-)) presented with the question: what kind of background threading should I use in this particular scenario? You are in .NET presented with the following options:

1) BackgroundWorker (System.ComponentModel.BackgroundWorker)
2) ThreadPool (System.Threading.ThreadPool)
3) Thread (System.Threading.Thread)
4) Task/Task<T> (System.Threading.Task; .NET 4 only)

BackgroundWorker (BGW):
This component can be used if you are doing work which should ultimately interact with the UI. The BackgroundWorker communicates using events raised on the user interface thread (see below), hence it is a good candidate for UI applications.

image

static void Main(string[] args)
{
var p = new Person();

//BGW

var bgw = new BackgroundWorker();
bgw.DoWork += bgw_DoWork;
bgw.RunWorkerCompleted += bgw_RunWorkerCompleted;
bgw.RunWorkerAsync(p); //start working, pass in Person class 'p'
}

//running on UI-thread
static void bgw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
throw new NotImplementedException();
}

//running on background thread
static void bgw_DoWork(object sender, DoWorkEventArgs e)
{
throw new NotImplementedException();
}

As seen in the above figure – the “RunWorkerCompleted” event is raised on the UI-thread (the backgroundworker handles the marshalling) and you can safely manipulate UI-controls from the eventhandler listening to RunWorkerCompleted event. Technically, the BGW raises the event on the calling thread; but as this is the UI-thread in the above scenario, you are effectively seeing an event raised on the UI-thread.


ThreadPool (TP):
This is an easy way of offloading tasks to the .NET threadpool. You basically compose a “task” (method) and send this off by queuing the task to the threadpool. It is a fire-and-forget way of programming. If you intend to interact with the UI afterwards, you should be aware that the operation is running in a non-UI thread!


image

static void Main(string[] args)
{
//thread pool
var p = new Person();
ThreadPool.QueueUserWorkItem(ThreadPoolWorker, p);
}

static void ThreadPoolWorker(object stateObject)
{
//do long running stuff with "stateObject"

}

Thread:
This is the hardcore way of doing multithreading. All is left to the developer, but you are in this way given full control of almost any property on the thread.

static void Main(string[] args)
{
//
var p = new Person();

var ts = new ParameterizedThreadStart(WorkMethod);
var t = new Thread(ts);
t.Name = "my thread";
t.Priority = ThreadPriority.Highest; //set high priority
t.Start(p); //pass in Person object
}


static void WorkMethod(object state)
{
//do stuff with state-object
}

Task/Task<T>:
This is presented as the future of multithreading. It is the way multithreading should be made, according to the “dark empire” (MS). The terms and concepts originally comes from TaskParallelLibrary (TPL), which was an incubation project from the PnP group in MS.

static void Main(string[] args)
{
//
var p = new Person();

var t = new Task(WorkMethod, p); //create new task, pass in Person
t.Start(); //schedule task (will start afterwards)
}


static void WorkMethod(object p)
{
//do stuff with state-object
}

There are a large number of tweaks that can be set on the Task/Task<T>. These are not shown, but allows you do control a large number of things.


Technorati Tags: ,

2 comments:

Josh said...

awesome analysis of the different wasy to accomplish threading.

Jassim Makki said...

Thank you very much.
This was helpful enough.