Multithreaded Programming in .Net with C# – Aggregated Exceptions


Introduction

This may seem like an odd topic for inclusion in my multithreaded in C#, with the .Net 4.0 framework. If you read on you will see why this is  a topic for consideration when programming using the .Net 4.0 Framework. When you see why the designers of the .Net Framework included the AggregateException Class you will see that there is a use case here which needed to be addressed.

Background

My previous blog post in this series was: Parallel Programming in .Net – Resources.

The Prompt For this Blog Post

Another resource:   Aggregating Exceptions or http://msdn.microsoft.com/en-au/magazine/ee321571.aspx

This is an interesting article on the AggregateException Class. This class is heavily used in the .Net Framework parallel support classes. Why? Read on for some explanations as to why the .Net Framework needed aggregated exceptions.

Single Threaded Exception Model

In single the single threaded programming model, one thread can only throw one exception at a time.

The following is a very simple example of exception processing in a single threaded environment. What it does show is that only one exception can be “active” at once.

private void method_a()
{
    try
    {
        method_b();
    }
    catch (NotImplementedException ex)
    {
        Debug.WriteLine(ex);
    }
}

private void method_b()
{
    throw new NotImplementedException();
}

Multiple Threaded Exception Model

In the multiple threading model you can potentially have multiple exceptions being thrown (one from each thread executing).

The following is a very simple example. There are a couple of point to note:

  • I don’t know how many exceptions will be thrown.
  • The number of exceptions depends on a number of factors wedged into the Parallel.For method.
    • How many CPU’s (or hardware threads) the machine has. The implementation scales out to what the machine has.
    • The implementation could called from another Parallel.For (or any other Framework Parallel method – including Parallel LINQ), so again the number of threads available is unknown.
    • The implementation has it’s own scale across algorithms. So again depending on the way the algorithm reacts to the current workload, we could get any number of threads.
private void root_Method()
{
    Parallel.For(1, 20, a=> {
        throw new NotImplementedException(a.ToString());
    });
}

There are a number of things which should be made clear. These are:

  1. We don’t know how many exceptions the caller should get.
  2. The ordinary exception cannot cater for more than one “meaning”. The Exception Class has an (just one) inner exception only.
  3. How does the implementation of Parallel.For decide which exception it should pass back from an arbitrary delegate (or, any code you like).

Why We Need Aggregated Exceptions?

The above starts to outline the use case for an aggregated exception, or more to the point an exception which can contain multiple exceptions. When you have multiple threads of execution each of those threads could throw an exception. These exceptions should go back to the thread which propagated the multiple threads. The caller should be “told” about all of the problems which occurred. As a result the .Net Framework “packs” all of these exceptions which occurred in the parallel operations into one exception which is passed (thrown) back to the caller. Acting as a container for all exceptions generated in a function is the function which the AggregateException Class performs.

The Structure of the AggregateException Class Class

The following code snippet is lifted from the MSDN article Aggregating Exceptions. I have included the code here so that I can highlight some of the additions that the AggregateException Class has, when compared to the “normal” exception classes.

[Serializable]
[DebuggerDisplay("Count = {InnerExceptions.Count}")]
public class AggregateException : Exception
{
    public AggregateException();
    public AggregateException(params Exception[] innerExceptions);
    public AggregateException(IEnumerable<Exception> innerExceptions);
    public AggregateException(string message);
    public AggregateException(string message, Exception innerException);
    public AggregateException(string message,
        params Exception[] innerExceptions);
    public AggregateException(string message,
        IEnumerable<Exception> innerExceptions);

    public AggregateException Flatten();
    public void Handle(Func<Exception, bool> predicate);

    public ReadOnlyCollection<Exception> InnerExceptions { get; }
}

AggregateException.InnerExceptions Propertyimage

This is where the exceptions from the multiple threads are stored. There is a subtle nuance in this storage structure, which is that it is a hierarchical representation of the exceptions thrown.

The following diagram attempts to show that one AggregatedException can contain other Aggregated Exceptions, and ordinary exceptions. The .Net Framework will generate another “level” (insert another aggregated exception) when there is another level of the parallel support in the Framework is invoked. For example, a Parallel.For which invokes a child Parallel.For. These parent child relationships are preserved in the aggregated exception structure which the Framework generates.

AggregateException Constructor

It is worth noting that the constructors for the AggregatedException include the ability to construct an AggregatedException from collections of exceptions. As you would expect, when building a container object.

AggregateException.Flatten Method

This is an interesting method which has been included into the implementation of the AggregatedException. It simply flattens the hierarchal, or nested, structure which the AggregatedException contains into a single level representation. This representation is then ideal for applying LINQ to the inner exceptions collection, and “pulling” out the exceptions you are interested in.

The following is a non functional piece of code, but demonstrates the use of the Flatten method with LINQ.

AggregateException sample = new AggregateException();
var interesting_exceptions = from ex in sample.Flatten().InnerExceptions
                             where ex is DivideByZeroException
                             select ex;

AggregateException.Handle Method

The handle method is another way of working with the AggregatedException an the collection of exceptions which it can contain. This method produces an aggregated exception which contains just the exceptions which do not satisfy the predicate supplied.

try
{
    sample.Flatten().Handle(e => e is DivideByZeroException);
}
catch (AggregateException ex)
{
    // Sample minus the DivideByZeroExceptions
    Debug.WriteLine(ex);
}

Conclusions

I hope that this discussion of the AggregateException Class proves useful.

It is a part of the .Net 4.0 Framework which undoubtable any developer producing multithreaded code will need to deal with.

Advertisements

, , , , , , , , ,

  1. Leave a comment

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

%d bloggers like this: