CodeGym /Courses /C# SELF /Canceling operations: Canc...

Canceling operations: CancellationToken

C# SELF
Level 60 , Lesson 4
Available

1. Getting to know CancellationToken

Imagine this: you start a long file download and then suddenly remember your Internet plan is metered and gigabytes are precious. Or a user got confused, started a computation, then decided they don't need it. They want to hit "Cancel" and not wait. Modern apps need to be responsive, so we must be able to send a stop signal at any time and correctly interrupt an async operation.

That's exactly what the cancellation infrastructure in .NET is for — the CancellationToken.

CancellationToken (literally "cancellation token") is a special object you pass into your long-running operation. At any point you can signal cancellation via a CancellationTokenSource, and the operation should periodically check the token (for example, IsCancellationRequested) and terminate cleanly, calling ThrowIfCancellationRequested() when needed.

How is it organized? (Short)

  • There is a CancellationTokenSource object that "creates" tokens and can cancel them (method Cancel()).
  • The CancellationToken itself is a "signal flag" that you can hand out to many operations (via the Token property on the source).
  • An operation periodically checks the token: if cancellation is requested, it stops working (or throws OperationCanceledException).

Analogy: you're the boss (you are the CancellationTokenSource). You give your team "badges" (those are CancellationTokens). When you decide it's time to cancel everything, you raise the red flag — and everyone with a badge retreats immediately, leaving their half-eaten lunch.

2. How to use CancellationToken

Create a cancellation token source (CancellationTokenSource)

var cts = new CancellationTokenSource();

Get the token itself (CancellationToken)

CancellationToken token = cts.Token;

Pass the token into an async method

Most built-in .NET async methods accept a parameter of type CancellationToken. For example, HttpClient.GetAsync, Stream.ReadAsync, Task.Delay, and others.

Example — a cancellable delay:

await Task.Delay(10000, token); // Wait 10 seconds — but it can be canceled!

Request cancellation (for example, by a button or a timer)

cts.Cancel(); // All operations that received this token will learn about the cancellation 

Check the token inside a method

Inside your methods (especially if the work is long and iterative) you need to regularly check the cancellation flag and throw OperationCanceledException if cancellation is requested:

token.ThrowIfCancellationRequested();

Or just check the property:

if (token.IsCancellationRequested)
{
    // Release resources, exit the method
}

3. Example: Let's add cancellation to our tutorial app

Suppose we have an app that downloads data from a website. Let's add the ability to cancel the download if the user changes their mind.

Basic async download example

using System;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;

class Downloader
{
    public async Task DownloadAsync(string url)
    {
        var client = new HttpClient();
        string content = await client.GetStringAsync(url); // Without cancellation
        Console.WriteLine("Download completed!");
    }
}

Adding CancellationToken

public async Task DownloadAsync(string url, CancellationToken token)
{
    var client = new HttpClient();
    string content = await client.GetStringAsync(url, token); // Now with cancellation support!
    Console.WriteLine("Download completed!");
}

Controlling cancellation from the caller

static async Task Main(string[] args)
{
    var downloader = new Downloader();
    var cts = new CancellationTokenSource();

    Console.WriteLine("Enter URL to download:");
    string url = Console.ReadLine();

    var downloadTask = downloader.DownloadAsync(url, cts.Token);

    Console.WriteLine("Press any key to cancel the download...");
    Console.ReadKey();

    cts.Cancel(); // Cancellation signal

    try
    {
        await downloadTask;
    }
    catch (OperationCanceledException)
    {
        Console.WriteLine("Download canceled by the user!");
    }
}

That’s it! Now the user can interrupt the operation at any time.

4. Interaction between CancellationTokenSource and methods

flowchart TD
    A["User code (Main)"] -- creates --> B["CancellationTokenSource"]
    B -- issues --> C["CancellationToken"]
    C -- passed to --> D["Async operation"]
    A -- calls Cancel() --> B
    D -- periodically checks --> C
    C -- signals cancellation to --> D
    D -- throws Exception or finishes work --> A

5. Handling cancellation

When an operation receives a cancellation token, there are two behavior options:

.NET methods will throw the exception themselves.
If you call standard methods like Stream.ReadAsync, HttpClient.GetAsync, or Task.Delay, and pass them the token — as soon as Cancel() is called, those methods will throw OperationCanceledException on their own. You just need to catch that exception.

Your custom async code.
If you implement a long-running operation yourself, e.g., iterative processing or heavy calculations, it's your responsibility to regularly check token.IsCancellationRequested (or call token.ThrowIfCancellationRequested()) to react to cancellation properly.

Example: a "long" operation with manual cancellation checks

public async Task CalculatePrimesAsync(int max, CancellationToken token)
{
    for (int i = 2; i < max; i++)
    {
        token.ThrowIfCancellationRequested(); // Check for cancellation

        if (IsPrime(i))
        {
            Console.WriteLine($"Prime number: {i}");
            await Task.Delay(100, token); // Let it "rest" (can be canceled)
        }
    }
    Console.WriteLine("Calculation finished!");
}

private bool IsPrime(int n)
{
    for (int i = 2; i <= Math.Sqrt(n); i++)
        if (n % i == 0) return false;
    return true;
}

6. Useful nuances

Methods and classes that support CancellationToken

Class/method Supports CancellationToken? Usage example
Task.Delay
await Task.Delay(1000, token);
HttpClient.GetAsync
await client.GetAsync(url, token);
Stream.ReadAsync
await stream.ReadAsync(buffer, 0, len, token);
Task.Run
Task.Run(() => ..., token);
File.ReadAllTextAsync
await File.ReadAllTextAsync(path, token);
Thread.Sleep
Does not support it; better to use Task.Delay
Your methods ✔ (if you add support!)
MyLongMethod(token)

Lifecycle of a cancellable operation

sequenceDiagram
    participant User
    participant Main
    participant CancellationTokenSource
    participant AsyncOperation

    User->>Main: Start operation
    Main->>CancellationTokenSource: Create CTS
    Main->>AsyncOperation: Start and pass CancellationToken
    User->>Main: Presses "Cancel"
    Main->>CancellationTokenSource: Calls Cancel()
    AsyncOperation->>AsyncOperation: Notices cancellation (\nIsCancellationRequested)
    AsyncOperation-->>Main: Throws OperationCanceledException
    Main->>User: Shows message "Operation canceled"

Where it's used in real life

  • UI apps: Abort long downloads, computations, file work if the user wants to close the window or cancel an action.
  • Server apps: If a client drops the connection — it's better to cancel request processing right away to avoid wasting resources.
  • Big data processing: Tasks can be very long — always provide a way to stop calculations or migrations.
  • Hardware integration: Scanning, printing and other operations sometimes need an urgent stop — cancellation support is mandatory there.

7. Common mistakes when working with CancellationToken

Mistake #1: Ignoring token checks.
If an operation doesn't check token.IsCancellationRequested or call ThrowIfCancellationRequested(), it won't stop on cancellation and will waste resources.

Mistake #2: Mishandling OperationCanceledException.
If you don't catch OperationCanceledException, the app may terminate unexpectedly. Always use try-catch to handle cancellation.

Mistake #3: Improper resource management on cancellation.
Cancellation does not automatically roll back changes (e.g., files or DB). You need to manually clean up resources in a catch block.

Mistake #4: Passing an already canceled token.
If the token is already canceled, the method will throw immediately, which can break logic if not accounted for.

2
Task
C# SELF, level 60, lesson 4
Locked
Prime Number Search with Cancellation Support
Prime Number Search with Cancellation Support
1
Survey/quiz
Task vs Thread Comparison, level 60, lesson 4
Unavailable
Task vs Thread Comparison
Parallel Data Processing
Comments
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION