Exceptions and Parallel Loops
The sixth part of the Parallel Programming in .NET tutorial is the last instalment that examines the parallel loops. This article discusses how exceptions are thrown by code within a parallel loop and how they can be handled.
When an exception is thrown from within a sequential loop the normal flow of the program is interrupted. Control passes to the next available catch block or, if no appropriate try / catch statements are present, the unhandled exception is passed to the .NET runtime and the program is aborted. When a try / catch block is present but it not within the loop, no further iterations are executed and the current iteration is terminated early.
When you are working with parallel For or ForEach loops the handling of exceptions is complicated somewhat. When an exception is thrown on one thread of execution, it is likely that there are other iterations of the loop executing in parallel. These cannot be simply terminated as this could lead to inconsistencies. To prevent such data errors, the iterations of the loop that have already been scheduled on other threads will continue. This is similar to when calling the ParallelLoopState.Stop method to terminate a parallel loop.
That parallel iterations continue after an exception generates a second problem. Namely, what happens if other iterations also throw exceptions? Clearly we would not want to have a single exception thrown by the loop when there have been two or more problems. It is important to capture every exception in order to gracefully recover. To allow all of the exceptions to be gathered together, the .NET framework provides the AggregateException class.
The AggregateException class is a subclass of Exception so provides all of the standard exception functionality. In addition, it has a property that holds a collection of inner exceptions. When thrown by a parallel loop, all of the encountered exceptions are included in the property, ensuring that no exception details are lost. It's important to note that an AggregateException will be thrown even if only one exception is encountered during the processing of the loop. Other exceptions can only be generated if there is a problem with the loop command itself, such as the action delegate that defines the loop body being null.
In the following sections we'll demonstrate exception handling for parallel loops. To provide simplified access to the loop methods add the following using directive:
7 September 2011