Canceling Continuations

The techniques to handle cancellations for single Tasks, which we covered in the previous chapter, can be applied to continuations. The Task.ContinueWith(), TaskFactory.ContinueWhenAll(), and TaskFactory.ContinueWhenAny() methods all have overloaded versions that accept a CancellationToken, which you can obtain by creating an instance of CancellationTokenSource.

Listing 4-7 demonstrates canceling continuations. An antecedent Task is created and waits using a CancellationToken wait handle. When the user presses the enter key, the CancellationTokenSource, and therefore the antecedent Task, are cancelled.

Listing 4-7. Cancelling Continuations using System;

using System.Threading;

using System.Threading.Tasks;

namespace Listing_07 {

class Listing_07 {

static void Main(string[] args) {

// create a cancellation token source CancellationTokenSource tokenSource = new CancellationTokenSource();

// create the antecedent task Task task = new Task(() => { // write out a message Console.WriteLine("Antecedent running"); // wait indefinately on the token wait handle tokenSource.Token.WaitHandle.WaitOne(); // handle the cancellation exception tokenSource.Token.ThrowIfCancellationRequested(); }, tokenSource.Token);

// create a selective continuation

Task neverScheduled = task.ContinueWith(antecedent => { // write out a message

Console.WriteLine("This task will never be scheduled"); }, tokenSource.Token);

// create a bad selective contination Task badSelective = task.ContinueWith(antecedent => { // write out a message

Console.WriteLine("This task will never be scheduled"); }, tokenSource.Token, TaskContinuationOptions.OnlyOnCanceled, TaskScheduler.Current);

// create a good selective contiuation Task continuation = task.ContinueWith(antecedent => { // write out a message Console.WriteLine("Continuation running"); }, TaskContinuationOptions.OnlyOnCanceled);

// prompt the user so they can cancel the token Console.WriteLine("Press enter to Console.ReadLine(); // cancel the token source tokenSource.Cancel();

// wait for the good continuation continuation.Wait();

// wait for input before exiting Console.WriteLine("Press enter to Console.ReadLine();

Each of the three continuation Tasks behaves in a different way. The neverScheduled Task has been created with the same CancellationToken as the antecedent and so is never scheduled to be run.

The second Task, called badSelective, is created using the OnlyOnCanceled value from the TaskContinuationOptions enumeration. Unfortunately, it is created using the same CancellationToken as the antecedent, so the options and the token can never be in a state where the Task will be scheduled. Tasks that rely on the OnlyOnCanceled value should not share a CancellationToken with their antecedent. The final Task, named continuation, shows a selective continuation that will run properly when the antecedent is cancelled.

0 0

Post a comment