Continuation tasks in .NET TPL: cancelling continuation tasks

Tasks in .NET TPL make it easy to assign tasks that should run upon the completion of a certain task.

We saw in previous posts on TPL how to define continuation tasks. You’ll also find examples showing how to cancel tasks in TPL. Continuation tasks can be cancelled using the same techniques as with “normal” tasks. If you don’t know the basics, then make sure to check out the related posts on this page.

We declare the cancellation token source:

CancellationTokenSource cancellationTokenSource	= new CancellationTokenSource();

We then continue with the antecedent task and provide the token source in the constructor:

Task motherTask = Task.Factory.StartNew(() =>
{
	Console.WriteLine("Mother task running.");
	cancellationTokenSource.Token.WaitHandle.WaitOne();
	cancellationTokenSource.Token.ThrowIfCancellationRequested();
}, cancellationTokenSource.Token);

We wait indefinitely for the token source to be cancelled with the WaitOne() method.

The following continuation task is created with the same cancellation token. This has the effect that if the token source is cancelled then both the antecedent and the continuation tasks will be cancelled:

Task taskSharingCancellationToken = motherTask.ContinueWith(antecedent =>
{
	Console.WriteLine("This continuation task will never run as it shares the cancellation token with the antecedent.");
}, cancellationTokenSource.Token);

If you remove the token from the constructor then this continuation task will run after the antecedent has completed with an exception.

The following continuation task may seem correct at first as it should only run if the antecedent has been cancelled:

Task incorrectContinuation = motherTask.ContinueWith(antecedent =>
{
       Console.WriteLine("This task will never be scheduled");
}, cancellationTokenSource.Token, TaskContinuationOptions.OnlyOnCanceled, TaskScheduler.Current);

However, it also shares the same cancellation token as the antecedent, so it will never run. In other words if you want a continuation task to run even if the antecedent has been cancelled then do not share the same cancellation token across tasks.

The below task will run as it doesn’t share the cancellation token:

Task correctContinuation = motherTask.ContinueWith(antecedent =>
{
	Console.WriteLine("Continuation running as there's no cancellation token sharing.");
}, TaskContinuationOptions.OnlyOnCanceled);

We cancel the token and wait for the correct continuation task to finish:

cancellationTokenSource.Cancel();
correctContinuation.Wait();

View the list of posts on the Task Parallel Library here.

Advertisement

About Andras Nemes
I'm a .NET/Java developer living and working in Stockholm, Sweden.

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 )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

Elliot Balynn's Blog

A directory of wonderful thoughts

Software Engineering

Web development

Disparate Opinions

Various tidbits

chsakell's Blog

WEB APPLICATION DEVELOPMENT TUTORIALS WITH OPEN-SOURCE PROJECTS

Once Upon a Camayoc

Bite-size insight on Cyber Security for the not too technical.

%d bloggers like this: