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");
}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");
}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}");
}
}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
At a glance
- Purpose
- Applications on the .NET platform
- File extension
- .cs
- Runs in
- .NET runtime
- Usually used with
- .NET SDK and libraries
Specifications & further reading
Related C# documentation
async and await
The async and await keywords let you write asynchronous code that reads almost like ordinary sequential code. Marking a method async allows it to use await, which pauses execution at that point until the awaited operation completes, without blocking the calling thread - freeing it up to do other work in the meantime. This is essential for keeping applications responsive during I/O-bound work like network calls, file access, or database queries.Task & Task<T>
Task represents an asynchronous operation that may still be running, and Task<T> represents one that will eventually produce a value of type T. Tasks are the building block that async/await is built on top of - an async method actually returns a Task (or Task<T>) that the caller can await, check the status of, or attach continuations to.Task.WhenAll & Task.WhenAny
Task.WhenAll() lets you run multiple independent asynchronous operations concurrently and await all of them together, completing once every task finishes - much faster than awaiting them one at a time. Task.WhenAny() completes as soon as the first of several tasks finishes, useful for timeout patterns or taking whichever result arrives first.Async Pitfalls: void vs Task, ConfigureAwait
A few recurring mistakes trip up many C# developers new to async: using async void instead of async Task (which makes exceptions impossible to catch normally), and blocking on async code with .Result or .Wait() (which can cause a deadlock in contexts with a synchronization context, like older ASP.NET or WPF apps). Understanding these pitfalls up front avoids some of the most common async-related bugs.
The async and await keywords let you write asynchronous code that reads almost like ordinary sequential code. Marking a method async allows it to use await, which pauses execution at that point until the awaited operation completes, without blocking the calling thread - freeing it up to do other work in the meantime. This is essential for keeping applications responsive during I/O-bound work like network calls, file access, or database queries.Task & Task<T>
Task represents an asynchronous operation that may still be running, and Task<T> represents one that will eventually produce a value of type T. Tasks are the building block that async/await is built on top of - an async method actually returns a Task (or Task<T>) that the caller can await, check the status of, or attach continuations to.Task.WhenAll & Task.WhenAny
Task.WhenAll() lets you run multiple independent asynchronous operations concurrently and await all of them together, completing once every task finishes - much faster than awaiting them one at a time. Task.WhenAny() completes as soon as the first of several tasks finishes, useful for timeout patterns or taking whichever result arrives first.Async Pitfalls: void vs Task, ConfigureAwait
A few recurring mistakes trip up many C# developers new to async: using async void instead of async Task (which makes exceptions impossible to catch normally), and blocking on async code with .Result or .Wait() (which can cause a deadlock in contexts with a synchronization context, like older ASP.NET or WPF apps). Understanding these pitfalls up front avoids some of the most common async-related bugs.