Codectionary / Developer documentation / C#

CancellationToken

CancellationToken provides a standard, cooperative way to signal that an asynchronous operation should stop before it completes naturally. A CancellationTokenSource creates the token and controls when cancellation is requested; the token itself is passed into async methods, which check it periodically (or pass it to another cancellable operation) and can throw an OperationCanceledException to unwind cleanly.

Read the syntax

CancellationTokenSource creates a token and requests cancellation; the receiving operation must observe the token or pass it to APIs that do. Cancellation is cooperative, not forced termination.

ThrowIfCancellationRequested turns a request into OperationCanceledException. CancelAfter schedules a timeout; a method may instead inspect IsCancellationRequested and return cleanly.

Syntax

CancellationTokenSource cts = new CancellationTokenSource();\nawait SomeAsyncMethod(cts.Token);

Examples

Basic Cancellation

Creating a token source and cancelling an in-progress operation.

async Task CountAsync(CancellationToken token)
{
    for (int i = 1; i <= 10; i++)
    {
        token.ThrowIfCancellationRequested();
        Console.WriteLine(i);
        await Task.Delay(200, token);
    }
}

CancellationTokenSource cts = new CancellationTokenSource();

Task countTask = CountAsync(cts.Token);
await Task.Delay(500);
cts.Cancel();  // request cancellation after 500ms

try
{
    await countTask;
}
catch (OperationCanceledException)
{
    Console.WriteLine("Counting was cancelled");
}
  1. Creating a token source and cancelling an in-progress operation.
  2. CancellationTokenSource creates a token and requests cancellation; the receiving operation must observe the token or pass it to APIs that do. Cancellation is cooperative, not forced termination.
  3. The counter checks the token and passes it to Task.Delay. After about 500 ms, Cancel requests a stop; awaiting the task catches its cancellation exception and prints the message.

Cancellation with a Timeout

A very common pattern: automatically cancel an operation if it takes too long.

async Task<string> FetchDataAsync(CancellationToken token)
{
    await Task.Delay(3000, token);  // simulate a slow operation
    return "data";
}

using CancellationTokenSource cts = new CancellationTokenSource();
cts.CancelAfter(TimeSpan.FromSeconds(1));  // auto-cancel after 1 second

try
{
    string result = await FetchDataAsync(cts.Token);
    Console.WriteLine(result);
}
catch (OperationCanceledException)
{
    Console.WriteLine("Request timed out");
}
  1. A very common pattern: automatically cancel an operation if it takes too long.
  2. CancellationTokenSource creates a token and requests cancellation; the receiving operation must observe the token or pass it to APIs that do. Cancellation is cooperative, not forced termination.
  3. CancelAfter requests cancellation after one second, before the three-second delay completes. The catch prints Request timed out instead of data.

Checking IsCancellationRequested Manually

For tight loops without a natural await point, checking the flag directly can be more efficient than throwing.

void ProcessItems(List<int> items, CancellationToken token)
{
    foreach (int item in items)
    {
        if (token.IsCancellationRequested)
        {
            Console.WriteLine("Stopping early due to cancellation");
            return;
        }
        Console.WriteLine($"Processing {item}");
    }
}
  1. For tight loops without a natural await point, checking the flag directly can be more efficient than throwing.
  2. CancellationTokenSource creates a token and requests cancellation; the receiving operation must observe the token or pass it to APIs that do. Cancellation is cooperative, not forced termination.
  3. ProcessItems is only defined here and never called, so this snippet prints nothing. When called with a token, it returns before the next item once cancellation is requested.

Best practices

  • Accept a CancellationToken as the last parameter of any async method that might run for a while, so callers can opt into cancellation support
  • Pass the token through to every nested async call (Task.Delay(ms, token), HttpClient calls, etc.) so cancellation actually propagates, not just at the top level
  • Use CancelAfter() for straightforward timeout scenarios instead of manually managing a separate timer
  • Always dispose a CancellationTokenSource (via using) once you are done with it, to release its underlying resources

Runtime & versions

.NET runtime. Feature availability depends on the language and runtime version used by your project; consult the official reference below.

C# language reference

Specifications & further reading