Exception handling in the .NET Task Parallel Library with C#: a safety catch-all

Introduction

There can be situations that your application uses threads to such an extent that you either cannot put a try-catch block around every single Task.Wait, Task.WaitAll etc. calls or you simply forget it. There is a way to subscribe to all unhandled aggregate exceptions that the task scheduler encounters. You can then decide what to do with the exception there.

The task scheduler has an UnobservedTaskException event. It’s straightforward to subscribe to that even with the += operator.

TaskScheduler.UnobservedTaskException += TaskScheduler_UnobservedTaskException;

…where the event handler looks like this:

static void TaskScheduler_UnobservedTaskException(object sender, UnobservedTaskExceptionEventArgs e)
{
	e.SetObserved();
	((AggregateException)e.Exception).Handle(ex =>
	{
		Console.WriteLine("Exception type: {0}", ex.GetType());
		return true;
	});
}

The SetObserved() method tells the task scheduler that the exception has been taken care of so there’s no need for it to bubble up. The UnobservedTaskExceptionEventArgs object has an Exception property that must be cast to an AggregateException. From then on you can call the Handle() method of the aggregate exception as we saw before.

Start a couple of new tasks:

Task.Factory.StartNew(() =>
{
	throw new ArgumentException();
});

Task.Factory.StartNew(() =>
{
	throw new NullReferenceException();
});

Wait a bit for the tasks to finish:

Thread.Sleep(100);

Run the code with Ctrl+F5 and… er… nothing happens really. The event handler is never triggered. You won’t see the aggregate exception type printed on the console window. What happened? The UnobservedTaskException handler will be called when the tasks with the unhandled exception have been collected by the garbage collector. As long as we are holding a reference to the two tasks the GC will not collect them, and we’ll never see the exception handler in action.

If we want to force the event handler to be fired then you can add the following two lines just below the Thread.Sleep bit:

GC.Collect();
GC.WaitForPendingFinalizers();

Run the code again and you’ll see the exception messages in the console window.

Note the following: in .NET4.5 there’s a new configuration element that specifies whether unhandled task exceptions should terminate the application or not:

<ThrowUnobservedTaskExceptions
   enabled="true|false"/>

True: terminate the process if an unhandled exception is encountered.
False (default): the exact opposite of the True case

In .NET4 the default behaviour is to terminate the process as we saw. In .NET4.5 it’s the exact opposite: unhandled exceptions still cause the UnobservedTaskException event to be raised, but the process will not be terminated by default. The exception will be silently ignored. So if you want to simulate .NET4 behaviour in a multi-threaded .NET4.5 application you’ll need to set the above mentioned configuration setting to true in the config file.

View the list of posts on the Task Parallel Library here.

Advertisements

About Andras Nemes
I'm a .NET/Java developer living and working in Stockholm, Sweden.

2 Responses to Exception handling in the .NET Task Parallel Library with C#: a safety catch-all

  1. Jacob says:

    Great!

    However it’s too bad when we call GC.Collect manually. Any other suggestion?

    • Andras Nemes says:

      You don’t need to call GC.Collect() in your production code, it’s there only for demo purposes so that we can trigger what’s going to happen in a real scenario. //Andras

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

ultimatemindsettoday

A great WordPress.com site

Elliot Balynn's Blog

A directory of wonderful thoughts

Robin Sedlaczek's Blog

Developer on Microsoft Technologies

HarsH ReaLiTy

A Good Blog is Hard to Find

Softwarearchitektur in der Praxis

Wissenswertes zu Webentwicklung, Domain-Driven Design und Microservices

the software architecture

thoughts, ideas, diagrams,enterprise code, design pattern , solution designs

Technology Talks

on Microsoft technologies, Web, Android and others

Software Engineering

Web development

Disparate Opinions

Various tidbits

chsakell's Blog

Anything around ASP.NET MVC,WEB API, WCF, Entity Framework & AngularJS

Cyber Matters

Bite-size insight on Cyber Security for the not too technical.

Guru N Guns's

OneSolution To dOTnET.

Johnny Zraiby

Measuring programming progress by lines of code is like measuring aircraft building progress by weight.

%d bloggers like this: