cancellation tokens
programming
concurrency
task management
software development

Linking Cancellation Tokens

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

Introduction

Cancellation in .NET is cooperative: code requests a stop, and running work decides how quickly it can honor that request. Linking cancellation tokens is the standard way to combine multiple cancellation signals, such as a user clicking Cancel and a timeout expiring, without writing separate checks everywhere.

Why Linked Tokens Exist

Many async workflows have more than one reason to stop. A web request may need to stop if the client disconnects, if the server shutdown token fires, or if an internal timeout is reached. Passing only one token down the stack forces you to pick a single source, which means some cancellation conditions get lost.

CancellationTokenSource.CreateLinkedTokenSource solves that problem by creating a new token source that is canceled when any of the input tokens is canceled. Your downstream code only needs one token, but that token still reflects all upstream conditions.

This keeps APIs simple. A repository, HTTP client wrapper, or background worker can accept a single CancellationToken, while the caller stays free to combine user cancellation, deadline cancellation, and application lifetime cancellation.

Creating a Linked Token Source

The most common pattern is to combine a caller token with a timeout token.

csharp
1using System;
2using System.Net.Http;
3using System.Threading;
4using System.Threading.Tasks;
5
6public static class Downloader
7{
8    public static async Task<string> FetchAsync(
9        HttpClient client,
10        string url,
11        CancellationToken callerToken)
12    {
13        using var timeoutCts = new CancellationTokenSource(TimeSpan.FromSeconds(5));
14        using var linkedCts =
15            CancellationTokenSource.CreateLinkedTokenSource(callerToken, timeoutCts.Token);
16
17        using var response = await client.GetAsync(url, linkedCts.Token);
18        response.EnsureSuccessStatusCode();
19
20        return await response.Content.ReadAsStringAsync(linkedCts.Token);
21    }
22}

In this example, FetchAsync stops when either condition fires. If the caller cancels first, the linked token is canceled immediately. If the network call takes longer than five seconds, the timeout token cancels the linked source even though the caller did nothing.

The key detail is disposal. A linked token source registers callbacks on the tokens you pass in. Wrapping it in using ensures those registrations are released promptly.

Passing the Linked Token Through the Call Chain

Linking is only useful if every operation below you accepts the combined token. That means you should pass the linked token into I/O calls and into your own async methods instead of switching back to the original token.

csharp
1using System;
2using System.Threading;
3using System.Threading.Tasks;
4
5public static class ImportJob
6{
7    public static async Task RunAsync(CancellationToken shutdownToken, CancellationToken userToken)
8    {
9        using var linkedCts =
10            CancellationTokenSource.CreateLinkedTokenSource(shutdownToken, userToken);
11
12        await StepAsync("Load files", 500, linkedCts.Token);
13        await StepAsync("Transform data", 500, linkedCts.Token);
14        await StepAsync("Write records", 500, linkedCts.Token);
15    }
16
17    private static async Task StepAsync(string name, int delayMs, CancellationToken token)
18    {
19        token.ThrowIfCancellationRequested();
20        Console.WriteLine($"Starting {name}");
21
22        await Task.Delay(delayMs, token);
23
24        token.ThrowIfCancellationRequested();
25        Console.WriteLine($"Completed {name}");
26    }
27}

Notice that the worker methods do not care why cancellation happened. They just respect the token they were given. That separation keeps code testable and predictable.

Use linked tokens when independent cancellation sources should all stop the same unit of work. Good examples include request timeout plus caller cancellation, service shutdown plus job cancellation, and parent operation plus child deadline.

Do not link tokens just because you have access to several of them. If one token belongs to a broader lifetime and another belongs to a narrower child operation, it may be cleaner to pass the narrower token directly. Linking adds a small amount of overhead, so it is best used at meaningful boundaries rather than at every method call.

Common Pitfalls

One common mistake is creating a linked token source and then accidentally passing the original token into lower-level APIs. That defeats the purpose because the timeout or second cancellation source no longer applies.

Another mistake is forgetting to dispose the linked source. This is easy to miss in short-lived console programs, but in long-running services it can leave callback registrations hanging around longer than necessary.

A third pitfall is swallowing OperationCanceledException and treating it like a normal success path without checking which token fired. In some systems, user cancellation is expected, while timeout cancellation should be logged or counted differently. If that distinction matters, inspect the original token sources near the call site.

Finally, avoid calling Cancel on a token source you did not create. Linked sources are for combining signals, not for taking ownership of other components' lifecycles.

Summary

  • Link tokens when one operation should stop for multiple independent reasons.
  • Use CancellationTokenSource.CreateLinkedTokenSource to merge those signals into one token.
  • Pass the linked token through every async call that participates in the operation.
  • Dispose linked token sources so callback registrations are cleaned up.
  • Treat cancellation as a normal control flow path, but still distinguish timeout, shutdown, and user-initiated cases when your application needs that detail.

Related reading
Free course
Beginner
7 lessons
2 hours
Tackling System Design Interview Problems

A short course that equips you with the skills to approach system design interviews methodically.

Start the free course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

All Rights Reserved.