CancellationToken in C#
Amir Doosti
.Net Software Engineer | 20+ Years of Expertise | C#, .NET, Microservices Architecture
As I promised, in this Article we will discover CancellationToken and all its reated types and usage.
The CancellationToken in C# is a powerful feature of the .NET framework used to propagate notifications that an operation should be canceled. It allows cooperative cancellation between threads, tasks, and asynchronous operations. This mechanism is particularly useful for long-running operations where it may be necessary to stop the operation gracefully before it completes.
You will find the sample codes for this article in the following link in my GitHub:
How CancellationToken Works
The CancellationToken class doesn’t directly cancel anything by itself. Instead, it acts as a notification mechanism. The developer must implement the actual cancellation logic by checking the token's state periodically and then gracefully terminating the task or operation if cancellation is requested.
For a while forget about CancellationToken and suppose we want to break a simple “while loop” or in other word we want to cancel the action we are doing in the loop. In this scenario we can simply use a variable and change its value to cancel the loop:
bool myCancelationToken = false;
while (!myCancellationToken)
{
…
If (condition) then myCancellationToken = true;
…
}
In this code myCancellationToken variable doesn’t cancel anything directly but by changing it to true anywhere in the code, we signal the loop that should be cancelled.
Common Use Cases
CancellationTokenSource and CancellationToken
CancellationTokenSource:
CancellationToken:
Key Methods and Properties of CancellationToken
Key Methods of CancellationTokenSource
Supporting Cooperative Cancellation
Cancellation in C# is cooperative. This means the operations that can be canceled must support CancellationToken and check for cancellation periodically.
Best Practices for Using CancellationToken:
领英推荐
Creating and Using CancellationToken
The following example shows how to typically create and use CancellationToken:
CancellationToken token = cts.Token;
CancellationTokenSource cts = new CancellationTokenSource();
// Cancel after a delay of 2 seconds
cts.CancelAfter(TimeSpan.FromSeconds(2));
Console.WriteLine("Process is started and will cancel after 2 seconds ...");
// Checking for cancellation within a long-running task
await Task.Run(() =>
{
for (int i = 0; i < 10; i++)
{
if (token.IsCancellationRequested)
{
Console.WriteLine("Task was cancelled.");
return;
}
// Simulate work
Thread.Sleep(500);
Console.WriteLine($"Task iteration {i}");
}
}, token);
Usage in Asynchronous Methods
CancellationToken is often used with async and await to cancel asynchronous operations. Here’s a typical scenario:
public async Task ProcessDataAsync(CancellationToken cancellationToken)
{
for (int i = 0; i < 100; i++)
{
// Periodically check if cancellation is requested
cancellationToken.ThrowIfCancellationRequested();
// Simulate an asynchronous task
await Task.Delay(100, cancellationToken);
Console.WriteLine($"Processing data {i}% complete.");
}
}
public async Task RunAsync()
{
CancellationTokenSource cts = new CancellationTokenSource();
// Example: User cancels after 1 second
cts.CancelAfter(TimeSpan.FromSeconds(1));
try
{
await ProcessDataAsync(cts.Token);
}
catch (OperationCanceledException)
{
Console.WriteLine("Operation was canceled.");
}
}
Example: Canceling Long-Running I/O Bound Task
Consider a file download operation that may need to be canceled mid-way.
public async Task DownloadFileAsync(string url, string destinationPath, CancellationToken cancellationToken)
{
using (var httpClient = new HttpClient())
using (var response = await httpClient.GetAsync(url, HttpCompletionOption.ResponseHeadersRead, cancellationToken))
using (var fileStream = new FileStream(destinationPath, FileMode.Create, FileAccess.Write, FileShare.None, 4096, true))
using (var responseStream = await response.Content.ReadAsStreamAsync(cancellationToken))
{
byte[] buffer = new byte[8192];
int bytesRead;
while ((bytesRead = await responseStream.ReadAsync(buffer, 0, buffer.Length, cancellationToken)) > 0)
{
await fileStream.WriteAsync(buffer, 0, bytesRead, cancellationToken);
cancellationToken.ThrowIfCancellationRequested();
}
}
}
Handling Canceled Tasks
If a task is canceled via a CancellationToken, it will usually throw an OperationCanceledException. Here’s an example of handling that exception:
public async Task DownloadMountainImage()
{
var url = @"https://upload.wikimedia.org/wikipedia/commons/6/6b/Big_Four_Mountain.jpg";
var destinationPath = Path.Combine(Directory.GetCurrentDirectory() + "mountain.jpg");
CancellationTokenSource cts = new CancellationTokenSource();
CancellationToken token = cts.Token;
// Cancel after a delay of 2 seconds
cts.CancelAfter(TimeSpan.FromMilliseconds(50));
try
{
Console.WriteLine("Start downloading mountain image ...");
await DownloadFileAsync(url, destinationPath, token);
}
catch (OperationCanceledException)
{
Console.WriteLine("Download was canceled.");
}
}
Linked CancellationTokenSource
Sometimes, multiple cancellation sources are involved. You can create a CancellationTokenSource that is linked to multiple tokens. In this case they act as OR which means if one of them get signal, then the operation should cancel:
CancellationTokenSource cts1 = new CancellationTokenSource();
CancellationTokenSource cts2 = new CancellationTokenSource();
CancellationTokenSource linkedCts = CancellationTokenSource.CreateLinkedTokenSource(cts1.Token, cts2.Token);
Task.Run(() => {
// Some work that can be canceled by either cts1 or cts2
}, linkedCts.Token);
// Cancel from either source
cts1.Cancel();
Timeout-based Cancellation
You can use CancelAfter to automatically cancel an operation after a specific duration:
Pros and Cons of CancellationToken
CancellationTokenSource cts = new CancellationTokenSource(TimeSpan.FromSeconds(10)); // Auto-cancel after 10 seconds
try
{
await LongRunningOperation(cts.Token);
}
catch (OperationCanceledException)
{
Console.WriteLine("The operation timed out and was canceled.");
}
Pros:
Cons:
Conclusion
CancellationToken is a powerful tool in the .NET framework for handling cancellation in a cooperative and controlled manner. By passing a CancellationToken through your asynchronous methods, you enable the ability to gracefully stop operations, clean up resources, and provide better user experience for cancelable long-running tasks.
In complex operations, proper use of CancellationTokenSource and CancellationToken is essential for building responsive, cancellable, and scalable applications.
#cancellation #canellationtoken #signaling #async #task #csharp
Good description of cancellation tokens.