ThreadPool vs. Tasks
.NET 4.0 includes a new few new classes called Tasks, which are part of the Task Parallel Library. You can learn all about them in an article by my friend Sacha on Code Project.
The TPL is useful, but I'm starting to see a lot of coders using the Task
class. I may be an old fuddy-duddy, but I can't quite understand what advantage Task
gives me over plain old ThreadPool in .NET 2.0. Here are some examples of how the Tasks "features" would be implemented using ThreadPool.
Starting a task
ThreadPool.QueueUserWorkItem(delegate
{
DoSomeWork();
});
Waiting for a task to complete
var handle = new ManualResetEvent(false);
ThreadPool.QueueUserWorkItem(delegate
{
DoSomeWork();
handle.Set();
});
handle.WaitOne();
Returning
int result = 0;
ThreadPool.QueueUserWorkItem(delegate
{
DoSomeWork();
result = 42;
handle.Set();
});
handle.WaitOne();
Console.WriteLine(result);
Chaining tasks
var handle = new AutoResetEvent(false);
ThreadPool.QueueUserWorkItem(delegate
{
DoSomeWork();
handle.Set();
});
handle.WaitOne();
ThreadPool.QueueUserWorkItem(delegate
{
DoSomeMoreWork();
handle.Set();
});
handle.WaitOne();
Waiting for multiple tasks to complete
var handle1 = new ManualResetEvent(false);
var handle2 = new ManualResetEvent(false);
ThreadPool.QueueUserWorkItem(delegate
{
DoSomeWork();
handle1.Set();
});
ThreadPool.QueueUserWorkItem(delegate
{
DoSomeMoreWork();
handle2.Set();
});
WaitHandle.WaitAll(new WaitHandle[] { handle1, handle2 });
Exception handling
var handle = new ManualResetEvent(false);
Exception error = null;
ThreadPool.QueueUserWorkItem(delegate
{
try
{
DoSomeWork();
}
catch (Exception ex)
{
error = ex;
}
finally
{
handle.Set();
}
});
handle.WaitOne();
if (error != null)
Console.WriteLine("Error! " + error);
Word of caution: you should probably always do this when using ThreadPool, since exceptions thrown on a ThreadPool thread will tear down the AppDomain if not caught
Cancellation
var cancel = false;
ThreadPool.QueueUserWorkItem(delegate
{
while (!cancel)
{
Thread.Sleep(100);
}
});
cancel = true;
Note: this is like a gazillion times more complex in Tasks
Dispatching to UI thread
var dispatcher = Application.Current.Dispatcher;
ThreadPool.QueueUserWorkItem(delegate
{
DoSomeWork();
dispatcher.BeginInvoke(new Action(() => progressBar.Value += 10));
DoSomeMoreWork();
dispatcher.BeginInvoke(new Action(() => progressBar.Value += 10));
});
Being notified when a task is complete without blocking
Action<int> done = (int x) => Console.WriteLine("Done! " + x);
ThreadPool.QueueUserWorkItem(delegate
{
DoSomeWork();
done(42);
});
So help me learn the Task
API - how would using Task
make the examples above look better?