Cancellation Tokens in C#
Introduction to Cancellation Tokens
Asynchronous programming in C# often involves long-running operations that might need to be canceled. This is where Cancellation Tokens come into play. Cancellation tokens allow cooperative cancellation between threads, tasks, or other asynchronous operations.
Creating a Cancellation Token
To create a cancellation token, you need a CancellationTokenSource. The Token property of this source gives you the CancellationToken:
var cts = new CancellationTokenSource(); CancellationToken token = cts.Token;
Using Cancellation Tokens in Asynchronous Methods
To use a cancellation token in an asynchronous method, you need to pass it as an argument. Here is an example using Task.Run:
var cts = new CancellationTokenSource(); CancellationToken token = cts.Token; Task.Run(() => { for (int i = 0; i < 10; i++) { if (token.IsCancellationRequested) { Console.WriteLine("Task was cancelled."); return; } Console.WriteLine($"Task iteration {i}"); Thread.Sleep(1000); // Simulate work } }, token);
Canceling a Task
To cancel a task, you call the Cancel method on the CancellationTokenSource:
var cts = new CancellationTokenSource(); CancellationToken token = cts.Token; Task task = Task.Run(() => { for (int i = 0; i < 10; i++) { if (token.IsCancellationRequested) { Console.WriteLine("Task was cancelled."); return; } Console.WriteLine($"Task iteration {i}"); Thread.Sleep(1000); // Simulate work } }, token); // Cancel the task after 3 seconds Thread.Sleep(3000); cts.Cancel();
Handling OperationCanceledException
When a task is canceled, it throws an OperationCanceledException. You can handle this exception to perform cleanup or other actions:
var cts = new CancellationTokenSource(); CancellationToken token = cts.Token; Task task = Task.Run(() => { try { for (int i = 0; i < 10; i++) { token.ThrowIfCancellationRequested(); Console.WriteLine($"Task iteration {i}"); Thread.Sleep(1000); // Simulate work } } catch (OperationCanceledException) { Console.WriteLine("Task was cancelled."); } }, token); // Cancel the task after 3 seconds Thread.Sleep(3000); cts.Cancel();
Combining Multiple Cancellation Tokens
You can combine multiple cancellation tokens using CancellationTokenSource.CreateLinkedTokenSource:
var cts1 = new CancellationTokenSource(); var cts2 = new CancellationTokenSource(); CancellationTokenSource linkedCts = CancellationTokenSource.CreateLinkedTokenSource(cts1.Token, cts2.Token); CancellationToken token = linkedCts.Token; Task task = Task.Run(() => { try { for (int i = 0; i < 10; i++) { token.ThrowIfCancellationRequested(); Console.WriteLine($"Task iteration {i}"); Thread.Sleep(1000); // Simulate work } } catch (OperationCanceledException) { Console.WriteLine("Task was cancelled."); } }, token); // Cancel the task using either of the original tokens Thread.Sleep(3000); cts1.Cancel();
Best Practices
When using cancellation tokens, consider the following best practices:
- Always check for cancellation in long-running tasks.
- Use ThrowIfCancellationRequested to throw an OperationCanceledException.
- Avoid swallowing OperationCanceledException unless you have a good reason.
- Always clean up resources in the catch block.
Conclusion
Cancellation tokens are a powerful tool in C# for managing long-running and asynchronous tasks. They allow for graceful and cooperative cancellation, enabling more responsive and robust applications. By following best practices and using the techniques outlined in this tutorial, you can effectively manage task cancellation in your own applications.