Avoid shooting yourself in the foot with Tasks and Async
Posted by Filip Ekberg on September 20 2012 6 Comments
Posted by Filip Ekberg on September 20 2012 6 Comments

Since the release of .NET 4.5, you’ve been able to use the RTM version of Async & Await. There are some things though that can lead to very weird behaviors in your applications, and a lot of confusion. Kevin (Pilchie) over at Microsoft just gave me heads up on some of these and I thought that I would share it with the rest of you!
There was a very interesting discussion around this subject in the ##roslyn channel on freenode with @ermau and @jrusbatch.
Avoid async void
When you’re doing asynchronous methods that just return void, there is no way to track when these methods are done.
Look at the following example:
{
public async void Biz()
{
await Foo();
}
public Task Foo()
{
return Task.Factory.StartNew(() =>
{
Task.Delay(2000);
Console.WriteLine("Done!");
});
}
}
If we create an instance of FooBar and call Biz(), there’s no way for us to wait for the task to finish. Normally we would want a reference to a Task that we could wait for to finish, but in this case we don’t! Avoid async void whenever you can.
Just change the method signature to async Task instead and you will be able to do:
The only reason you want to use async void is when you have an event handler that needs to await something. Such as a Click event handler like this:
{
var task = Task<string>.Factory.StartNew(() =>
{
Thread.Sleep(2000);
return string.Empty;
});
var data = await task;
MessageBox.Show(data);
}
Never getting that second exception when awaiting multiple results?
Consider that we have two asynchronous methods that both thrown an exception (almost at the same time), like these two methods here:
What would happen if we called the following method?
{
return await Foo() + await Bar();
}
We would indeed get an exception thrown. But we would only get One exception thrown! In fact, the only exception that we will get is the First exception being thrown.
This means that we would not see an aggregated exception list as we might expect.
Exceptions in Tasks don’t travel back to the caller
When working with multiple threads and the thread causes a problem that is unhandled, these are thrown back at the caller.
Look at this following example for instance:
When running this, we will see the following exception:
Unhandled Exception: System.Exception: Exception of type ‘System.Exception’ was thrown.
This is perfectly reasonable, it tears down the calling process!
But what about if this was a Task instead?
The following code spawns a new task and just throws a similar exception to what the thread example did above:
What happens when we run this? Nothing!
No exception were traveled back to the caller, this can cause potential confusions. This is actually by design and MSDN says the following about it:
In the .NET Framework 4, by default, if a
Taskthat has an unobserved exception is garbage collected, the finalizer throws an exception and terminates the process. The termination of the process is determined by the timing of garbage collection and finalization.To make it easier for developers to write asynchronous code based on tasks, the .NET Framework 4.5 changes this default behavior for unobserved exceptions. Unobserved exceptions still cause the
UnobservedTaskExceptionevent to be raised, but by default, the process does not terminate. Instead, the exception is ignored after the event is raised, regardless of whether an event handler observes the exception.
If we want the the .NET 4 behavior, we can re-enable the unobserved task exceptions by changing the applications app.config. Add the following to the app.config:
<runtime>
<ThrowUnobservedTaskExceptions enabled="true"/>
</runtime>
</configuration>
Since the exception will be thrown in the finalizer, we can test this by running the following:
Thread.Sleep(100);
GC.Collect();
GC.WaitForPendingFinalizers();
This will tear down the process as it did in .NET 4.0.
Unhandled Exception: System.AggregateException: A Task’s exception(s) were not observed either by Waiting on the Task or accessing its Exception property. As a result, the unobserved exception was rethrown by the finalizer thread. —> System.Exception: Exception of type ‘System.Exception’ was thrown.
Have you ever shot yourself in the foot with Tasks or Async? Leave your horror stories in the comment field!
?>
Filip Ekberg is a Senior Software Engineer working in the country with all the polar bears, author of a self-published C# programming book and overall in love with programming.





Pingback: Dew Drop – September 20, 2012 (#1,405) | Alvin Ashcraft's Morning Dew
Thanks for the post – some good things to bear in mind.
An observation:-
I don’t think I would ever expect an aggregate exception here. I would expect the exception from
, since effectively we are waiting on the first call and then waiting on the second call.
Pingback: Windows 8 Developer Links – 2012-09-21Dan Rigby | Dan Rigby
Good post. But I would not agree with first point.
First of all, your code will run the next line of code and that is how you know it has finished, regardless of returning a value or not. For example instead of
MessageBox.Show(data);
You can use
MessageBox.Show("Task was done");
Also there are many async operations in .NET Framework that do not return a value (i.e. they return Task instead of Task). For example, HttpContent.LoadIntoBufferAsync().
Pingback: Reading Notes 2012-10-01 | Matricis
Pingback: Don't deadlock with async and await