Cancellation Tokens in C#
Theodore Karropoulos

Theodore Karropoulos @tkarropoulos

About: Hello I am Theodoros, am a Software engineer with passion on new technologies, basketball and sports in general!

Location:
Greece
Joined:
Aug 4, 2020

Cancellation Tokens in C#

Publish Date: Dec 31 '22
33 6

Cancellation tokens in C# are used to signal that a task or operation should be cancelled. They allow for the cooperative cancellation of a task or operation, rather than aborting it forcibly.

Cancellation tokens in C# are used to signal that a task or operation should be cancelled. They allow for the cooperative cancellation of a task or operation, rather than aborting it forcibly.

There are two main ways to check if a cancellation token has been cancelled:

  • The IsCancellationRequested property
  • The ThrowIfCancellationRequested method

The IsCancellationRequested Property

The IsCancellationRequested property of the CancellationToken class is a Boolean value that indicates whether the associated cancellation token has been cancelled. It is set to true when the cancellation token is cancelled using the Cancel method of the CancellationTokenSource class, and is set to false when the cancellation token has not been cancelled or has been reset.

Here is an example of how the IsCancellationRequested property can be used in a task:

using System.Threading;

namespace CancellationTokensExample
{
    class Program
    {
        static void Main(string[] args)
        {
            // Create a cancellation token source
            var cts = new CancellationTokenSource();

            // Create a cancellation token from the source
            var token = cts.Token;

            // Start a task that will complete after a delay
            var task = Task.Factory.StartNew(() =>
            {
                for (int i = 0; i < 100; i++)
                {
                    // Check if the task has been cancelled
                    if (token.IsCancellationRequested)
                    {
                        // End the task
                        Console.WriteLine("Task cancelled");
                        return;
                    }

                    // Perform some work
                    Console.WriteLine("Task running");
                    Thread.Sleep(200);
                }

                // Task completed
                Console.WriteLine("Task completed");
            }, token);

            // Wait for a key press
            Console.ReadKey();

            // Cancel the task
            cts.Cancel();

            // Wait for the task to complete
            task.Wait(token);
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

In this example, a task is started using the Task.Factory.StartNew method and a cancellation token is passed as an argument. The task loops through a loop 100 times, performing some work and delaying for 200 milliseconds on each iteration.

Inside the loop, the task checks the IsCancellationRequested property of the cancellation token. If this property is true, it means that the cancellation token has been cancelled and the task should end. If the property is false, the task continues running.

After the task is started, the program waits for a key press from the user. When the user presses a key, the CancellationTokenSource object's Cancel method is called, which cancels the associated cancellation token and sets the IsCancellationRequested property to true. The task ends and a message is printed to the console.

The ThrowIfCancellationRequested Method

The ThrowIfCancellationRequested method of the CancellationToken class throws an OperationCanceledException if the cancellation token has been cancelled. This can be useful if you want to cancel a task or operation and throw an exception if it is cancelled.

Here is an example of how the ThrowIfCancellationRequested method can be used in a task:

using System;
using System.Threading;

namespace CancellationTokensExample
{
    class Program
    {
        static void Main(string[] args)
        {
            // Create a cancellation token source
            var cts = new CancellationTokenSource();

            // Create a cancellation token from the source
            var token = cts.Token;

            // Start a task that will complete after a delay
            var task = Task.Factory.StartNew(() =>
            {
                for (int i = 0; i < 100; i++)
                {
                    // Check if the task has been cancelled
                    token.ThrowIfCancellationRequested();

                    // Perform some work
                    Console.WriteLine("Task running");
                    Thread.Sleep(200);
                }

                // Task completed
                Console.WriteLine("Task completed");
            }, token);

            // Wait for a key press
            Console.ReadKey();

            // Cancel the task
            cts.Cancel();

            try
            {
                // Wait for the task to complete
                task.Wait(token);
            }
            catch (OperationCanceledException)
            {
                // Task was cancelled
                Console.WriteLine("Task cancelled");
            }
            catch (Exception ex)
            {
                // Handle other exceptions
            }
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

In this example, a task is started using the Task.Factory.StartNew method and a cancellation token is passed as an argument. The task loops through a loop 100 times, performing some work and delaying for 200 milliseconds on each iteration.

Inside the loop, the task calls the ThrowIfCancellationRequested method of the cancellation token. If the cancellation token has been cancelled, this method throws an OperationCanceledException.

After the task is started, the program waits for a key press from the user. When the user presses a key, the CancellationTokenSource object's Cancel method is called, which cancels the associated cancellation token. The task ends and an OperationCanceledException is thrown. The program catches the exception and prints a message to the console.

Comments 6 total

  • Kis Tamás
    Kis TamásJan 4, 2023

    Nice article! Please don't forget that CancellationTokenSource implements IDisposable so don't forget to use the using keyword eg.: using var cts = new CancellationTokenSource();

    • Theodore Karropoulos
      Theodore KarropoulosJan 5, 2023

      Hello @pkcrazy and thank you for your positive feedback and for pointing out that it is always a good practice to use using to dispose of objects that implement IDisposable. This allows the .NET framework to handle the cleaning up of resources associated with the object.

  • ali50m
    ali50mJan 6, 2023

    During my test, in the ThrowIfCancellationRequested example, I think token should be passed into task.Wait() function like below, or the exception OperationCanceledException can`t be catched.

        try
        {
            // Wait for the task to complete
            task.Wait(token); // <= pass in token here
        }
        catch(OperationCanceledException)
        {
            // Task was cancelled
            Console.WriteLine("Task cancelled");
        }
    
    Enter fullscreen mode Exit fullscreen mode
    • Theodore Karropoulos
      Theodore KarropoulosJan 7, 2023

      Hello @ali50m , Thank you for taking the time to read my post! The thing is, if you do not pass the cancellationToken to task.Wait(), an exception will still be thrown if the task is cancelled, but it will not be an OperationCanceledException. Instead, an AggregateException will be thrown, which will contain a TaskCanceledException as one of its inner exceptions. TaskCanceledException derives from OperationCanceledException. Either way, you are correct that in my example, since the OperationCanceledException is never thrown, the code will never handle it. I have already updated my example to pass the cancellationToken to task.Wait(). Thank you for pointing that out.

  • Jakob
    JakobJul 15, 2024

    In a simple comprehensive way clarified, well done

    • Theodore Karropoulos
      Theodore KarropoulosJul 20, 2024

      Thank you Jakob very much for taking the time to read my article! I am glad you found it interesting and helpful!

Add comment