Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Parallel.Invoke - Exception handling

My code runs 4 function to fill in information (Using Invoke) to a class such as:

class Person
{
    int Age;
    string name;
    long ID;
    bool isVegeterian

    public static Person GetPerson(int LocalID)
    {
        Person person;
        Parallel.Invoke(() => {GetAgeFromWebServiceX(person)}, 
                        () => {GetNameFromWebServiceY(person)},
                        () => {GetIDFromWebServiceZ(person)},
                        () => 
                        {
                           // connect to my database and get information if vegeterian (using LocalID)
                           ....
                           if (!person.isVegetrian)
                               return null
                           ....
                        });
     }
}

My question is: I can not return null if he's not a vegeterian, but I want to able to stop all threads, stop processing and just return null. How can it be achieved?

like image 859
Faruz Avatar asked Sep 16 '10 06:09

Faruz


1 Answers

To exit the Parallel.Invoke as early as possible you'd have to do three things:

  1. Schedule the action that detects whether you want to exit early as the first action. It's then scheduled sooner (maybe as first, but that's not guaranteed) so you'll know sooner whether you want to exit.
  2. Throw an exception when you detect the error and catch an AggregateException as Jon's answer indicates.
  3. Use cancellation tokens. However, this only makes sense if you have an opportunity to check their IsCancellationRequested property.

Your code would then look as follows:

var cts = new CancellationTokenSource();
try
{
    Parallel.Invoke(
        new ParallelOptions { CancellationToken = cts.Token },
        () =>
        {
            if (!person.IsVegetarian)
            {
                cts.Cancel();
                throw new PersonIsNotVegetarianException();
            }
        },
        () => { GetAgeFromWebServiceX(person, cts.Token) }, 
        () => { GetNameFromWebServiceY(person, cts.Token) },
        () => { GetIDFromWebServiceZ(person, cts.Token) }
    );
}
catch (AggregateException e)
{
    var cause = e.InnerExceptions[0];
    // Check if cause is a PersonIsNotVegetarianException.
}

However, as I said, cancellation tokens only make sense if you can check them. So there should be an opportunity inside GetAgeFromWebServiceX to check the cancellation token and exit early, otherwise, passing tokens to these methods doesn't make sense.

like image 69
Ronald Wildenberg Avatar answered Nov 09 '22 22:11

Ronald Wildenberg