BlackWaspTM

This web site uses cookies. By using the site you accept the cookie policy.This message is for compliance with the UK ICO law.

Parallel and Asynchronous
.NET 4.0+

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.

Throwing AggregateExceptions

Sometimes you will want to throw your own AggregateExceptions. For example, you may wish to execute every iteration of a parallel loop, even if some of those iterations throw exceptions. In order that the exceptions are not lost you can hold them in a collection during the loop and throw an AggregateException when the loop completes, initialising the InnerExceptions property with the list of captured exceptions. We will do this in the final example in this article.

When generating the collection we must use a class that is thread-safe to ensure that no exceptions are lost due to synchronisation problems. The .NET framework provides several such collections. One is ConcurrentQueue<T>, which provides a generic first-in, first-out queue structure that can be safely used in a parallel loop scenario. The ConcurrentQueue class in found in the System.Collections.Concurrent namespace.

using System.Collections.Concurrent;

For the last sample I've moved the parallel loop into its own method. This makes it easier to see how the exception handling is added. Before the loop starts we instantiate a new ConcurrentQueue<Exception> to hold any exceptions that are encountered. During the loop's execution, all exceptions are caught and added to the queue. If you wished to add your own custom exceptions you could either throw them within the try block or add them to the queue directly, depending upon the functionality required.

Once the loop has completed, the queue's Count property is checked to see if any exceptions where caught. If not, a message is displayed indicating that the program completed without error. If exceptions are present a new AggregationException is created, passing the collection of exceptions to its constructor. In the Main method the AggregateException is caught and each exception's Message property value is outputted.

static void Main()
{
    try
    {
        ParallelLoop();
    }
    catch (AggregateException ex)
    {
        foreach (Exception inner in ex.InnerExceptions)
        {
            Console.WriteLine(inner.Message);
        }
    }
}

static void ParallelLoop()
{
    var exceptions = new ConcurrentQueue<Exception>();

    Parallel.For(-10, 10, i =>
    {
        try
        {
            Console.WriteLine("100/{0}={1}", i, 100 / (i % 10));
        }
        catch (Exception ex)
        {
            exceptions.Enqueue(ex);
        }
    });

    if (exceptions.Count == 0)
        Console.WriteLine("No exceptions");
    else
        throw new AggregateException(exceptions);
}

/* OUTPUT

100/-5=-20
100/5=20
100/6=16
100/7=14
100/8=12
100/9=11
100/-8=-12
100/-9=-11
100/-4=-25
100/-3=-33
100/-7=-14
100/-6=-16
100/1=100
100/2=50
100/3=33
100/4=25
100/-2=-50
100/-1=-100
Attempted to divide by zero.
Attempted to divide by zero.

*/
7 September 2011