# TPL and Error Handling

As of .NET 4.0, the TPL or Task Parallel Library is king when it comes to parallelization. It allows for smooth, easy multi-threading for any application. There is a slight learning curve, however, and a major part of this is understanding how Exceptions bubble-up while using the TPL.

Let’s partake in a simple example. This code will create and run a task that throws an Exception, and then attempt to catch it:

static void Main(string[] args)
{
try
{
// Initialize a Task which throws exception
{
throw new Exception("Task broke!");
});
// Start the Task
}
// Attempt to catch the Task Exception
catch (Exception ex)
{
Console.WriteLine("Caught the TPL exception");
}

Console.WriteLine("End of method reached");
}


When we run it, we get this result:

The Exception was not caught. This is because the Task is run on a different thread, which has its own Stack memory and execution path, which consists of the code inside of the Task and not much else. As a result, when the Task is run, the flow of control returns to the next line in our application, unaware of the Task or its outcome. Once the Exception in the Task is thrown, it is thrown in a different scope, effectively outside of our Main method. It’s almost as if we ran an entirely different application, but attempted to catch its Exception in this application. This just won’t work.

static void Main(string[] args)
{
try
{
// Initialize a Task which throws exception
{
throw new Exception("Task broke!");
});
// Start the Task
// Wait for the Task to complete, thus keeping control of flow
}
// Attempt to catch the Task Exception
catch (Exception ex)
{
Console.WriteLine("Caught the TPL exception");
}

Console.WriteLine("End of method reached");
}


The output is as follows:

This time we were able to catch the Exception. Of note, the Exception which is thrown by Tasks is typically the AggregateException which allows you to catch multiple, often asynchronous Exceptions as one Exception (which is easier for a single thread to handle). A quick demo of this functionality (let’s have 5 threads each throw an Exception):

static void Main(string[] args)
{
try
{
// A List of Tasks

for (int i = 0; i < 5; i++)
{
// Initialize a Task which throws exception
{
throw new Exception("It broke!");
});
// Start the Task
// Add to List
}
// Wait for all Tasks to complete, thus keeping control of flow
}
// Attempt to catch the Task Exception
catch (AggregateException agex)
{
Console.WriteLine("Caught the TPL exception(s)");
// Output all actual Exceptions
foreach (var ex in agex.InnerExceptions)
{
Console.WriteLine(ex.Message);
}
}

Console.WriteLine("End of method reached");
}


And the output:

So as you can see, there are ways to handle Tasks throwing Exceptions, if you have your calling thread pause and wait for the Tasks to complete. This, of course, is not always practical so your other option is to handle the exception within the Task’s scope – just like you would with regular, single-threaded code. In effect you treat the code within the Task as isolated, single-threaded code, and catch and handle Exceptions accordingly. A slight mod to our application will show you this:

static void Main(string[] args)
{
for (int i = 0; i < 5; i++)
{
// Initialize a Task which throws exception
{
try
{
throw new Exception("It broke!");
}
catch (Exception ex)
{
// Output the Exception
Console.WriteLine(ex.Message);
}
});
// Start the Task
// Note: no longer waiting for Task to finish
}

Console.WriteLine("End of method reached");
}


And the result of this change:

Note the interesting results of this. Our main thread did not wait for the Tasks to complete, and so it the Task results were never returned back to the calling thread’s flow of control. As a result, the “End of method reached” text actually came before the threads crashed, because it happened sooner.