Continuation tasks in .NET TPL: make continuation conditional
March 14, 2014 Leave a comment
Tasks in .NET TPL make it easy to assign tasks that should run upon the completion of a certain task. You can also specify on what condition the continuation task should run.
We’ll need a basic object with a single property:
public class Series
{
public int CurrentValue
{
get;
set;
}
}
Declare and start a task that increases the CurrentValue in a loop and return the Series. This task is called the antecedent task in a chain of tasks.
Task<Series> motherTask = Task.Factory.StartNew<Series>(() =>
{
Series series = new Series();
for (int i = 0; i < 5000; i++)
{
series.CurrentValue++;
}
return series;
});
You can create other tasks that will continue upon the completion of the antecedent task. The default value is that the continuation task will be scheduled to start when the preceding task has completed. However, the Task constructor – and the task factory – let’s you supply a TaskContinuationOptions enumeration.
This is how you declare a default continuation task:
Task<int> firstContinuationTask
= motherTask.ContinueWith<int>((Task<Series> antecedent) =>
{
Console.WriteLine("First continuation task reporting series value: {0}", antecedent.Result.CurrentValue);
return antecedent.Result.CurrentValue * 2;
});
The first continuation task reads the Series object built by the antecedent, the “mother” task. It prints out the CurrentValue of the Series. The continuation task also returns an integer: the series value multiplied by two.
You can extend this declaration as follows:
Task<int> firstContinuationTask
= motherTask.ContinueWith<int>((Task<Series> antecedent) =>
{
Console.WriteLine("First continuation task reporting series value: {0}", antecedent.Result.CurrentValue);
return antecedent.Result.CurrentValue * 2;
}, TaskContinuationOptions.OnlyOnRanToCompletion);
Note the extra TaskContinuationOptions.OnlyOnRanToCompletion parameter. As the name implies it will only run if the antecedent has completed successfully: it has not been cancelled and has not thrown an unhandled exception.
Other important enumeration values:
- None: the default value, the continuation will run when the antecedent completes
- NotOnRanToCompletion: the opposite of OnlyOnRanToCompletion, i.e. only run if antecedent has been cancelled or has thrown an unhandled exception
- OnlyOnFaulted: if antecedent has thrown an unhandled exception
- NotOnFaulted: if antecedent has not thrown any unhandled exceptions
- OnlyOnCancelled: if antecedent has been cancelled
- NotOnCancelled: if antecedent has not been cancelled
Let’s declare a second continuation task:
Task secondContinuationTask
= firstContinuationTask.ContinueWith((Task<int> antecedent) =>
{
Console.WriteLine("Second continuation task reporting series value: {0}", antecedent.Result);
}, TaskContinuationOptions.NotOnRanToCompletion);
Note that it’s enough to start the first task, which we did with Task.Factory.StartNew. The continuation tasks will be scheduled automatically.
Provided that the mother task completes and the first continuation also completes the second continuation will not run due to the specified NotOnRanToCompletion option.
View the list of posts on the Task Parallel Library here.