Parallelism in .NET – Part 19, TaskContinuationOptions

My introduction to Task continuations demonstrates continuations on the Task class.  In addition, I’ve shown how continuations allow handling of multiple tasks in a clean, concise manner.  Continuations can also be used to handle exceptional situations using a clean, simple syntax.

In addition to standard Task continuations , the Task class provides some options for filtering continuations automatically.  This is handled via the TaskContinationOptions enumeration, which provides hints to the TaskScheduler that it should only continue based on the operation of the antecedent task.

This is especially useful when dealing with exceptions.  For example, we can extend the sample from our earlier continuation discussion to include support for handling exceptions thrown by the Factorize method:

// Get a copy of the UI-thread task scheduler up front to use later
var uiScheduler = TaskScheduler.FromCurrentSynchronizationContext();

// Start our task
var factorize = Task.Factory.StartNew(
    () =>
        {
            int primeFactor1 = 0;
            int primeFactor2 = 0;
            bool result = Factorize(10298312, ref primeFactor1, ref primeFactor2);
            return new {
                           Result = result,
                           Factor1 = primeFactor1,
                           Factor2 = primeFactor2
                       };
        });

// When we succeed, report the results to the UI
factorize.ContinueWith(task => textBox1.Text = string.Format("{0}/{1}  [Succeeded {2}]",
                                 task.Result.Factor1,
                                 task.Result.Factor2,
                                 task.Result.Result),
                        CancellationToken.None,
                        TaskContinuationOptions.NotOnFaulted,
                        uiScheduler);

// When we have an exception, report it
factorize.ContinueWith(task => 
                             textBox1.Text = string.Format("Error: {0}", task.Exception.Message),
                        CancellationToken.None,
                        TaskContinuationOptions.OnlyOnFaulted,
                        uiScheduler);

The above code works by using a combination of features.  First, we schedule our task, the same way as in the previous example.  However, in this case, we use a different overload of Task.ContinueWith which allows us to specify both a specific TaskScheduler (in order to have your continuation run on the UI’s synchronization context) as well as a TaskContinuationOption

In the first continuation, we tell the continuation that we only want it to run when there was not an exception by specifying TaskContinuationOptions.NotOnFaulted.  When our factorize task completes successfully, this continuation will automatically run on the UI thread, and provide the appropriate feedback.

However, if the factorize task has an exception – for example, if the Factorize method throws an exception due to an improper input value, the second continuation will run.  This occurs due to the specification of TaskContinuationOptions.OnlyOnFaulted in the options.  In this case, we’ll report the error received to the user.

We can use TaskContinuationOptions to filter our continuations by whether or not an exception occurred and whether or not a task was cancelled.  This allows us to handle many situations, and is especially useful when trying to maintain a valid application state without ever blocking the user interface.  The same concepts can be extended even further, and allow you to chain together many tasks based on the success of the previous ones.  Continuations can even be used to create a state machine with full error handling, all without blocking the user interface thread.

About Reed
Reed Copsey, Jr. - http://www.reedcopsey.com - http://twitter.com/ReedCopsey

Comments

3 Responses to “Parallelism in .NET – Part 19, TaskContinuationOptions”
  1. Werner says:

    The task “factorize” starts immediately (Factory.StartNew)
    the 2 Continuations are addeded after(!).
    WHAT if a exception occurs before the Faulted-Continuation is created/attached ?

    Regards
    Werner

    • Reed says:

      Werner,

      If an exception occurs, it’s “held” by the task. When you attach the continuation, it’s passed into the continuation, and must be handled. As far as the calling code occurs, it doesn’t matter if the exception happens before or after the continuation is attached – it’s handled identically.

      -Reed

Trackbacks

Check out what others are saying about this post...
  1. [...] This post was mentioned on Twitter by Vicente Cartas, Reed Copsey, Jr.. Reed Copsey, Jr. said: Blog series on Parallelism in .NET. Part 19, TaskContinuationOptions http://bit.ly/9QmRDe #csharp #dotnet #TPL [...]



Speak Your Mind

Tell us what you're thinking...
and oh, if you want a pic to show with your comment, go get a gravatar!