C# How to cancel a Task?

In the world of doing multiple things at the same time in programming, it’s really important to handle tasks well. C# has strong ways to deal with things happening at the same time, and it’s crucial to know how to stop tasks to make applications that react quickly and can handle lots of work. This guide will look at the CancellationToken and how it stops tasks in C#.

Understanding the CancellationToken

What is CancellationToken?

The CancellationToken is an important part of C#. It helps you stop asynchronous operations in a smooth way. You can give it to tasks so they can stop when asked.

Creating a CancellationToken

Creating and managing cancellation tokens is an important aspect of asynchronous programming in .NET. When dealing with scenarios where responsive and coordinated cancellation of multiple tasks is required, the CancellationToken and CancellationTokenSource classes provide a robust mechanism for achieving this.

In the following example, we demonstrate how to create a CancellationToken using a CancellationTokenSource and how to associate it with asynchronous tasks. We also simulate the cancellation of the tasks after a certain period.

Example:

using System;
using System.Threading;

class Program
{
    static void Main()
    {
        // Create a cancellation token source
        CancellationTokenSource cts = new CancellationTokenSource();

        // Get the cancellation token
        CancellationToken token = cts.Token;

        // Pass the token to the tasks
        // Task 1
        ThreadPool.QueueUserWorkItem(state => SomeTask(token));

        // Task 2
        ThreadPool.QueueUserWorkItem(state => SomeOtherTask(token));

        // Simulate cancellation after 3 seconds
        Thread.Sleep(3000);
        cts.Cancel();

        Console.ReadLine();
    }

    static void SomeTask(CancellationToken token)
    {
        while (!token.IsCancellationRequested)
        {
            // Task logic here
        }
    }

    static void SomeOtherTask(CancellationToken token)
    {
        while (!token.IsCancellationRequested)
        {
            // Task logic here
        }
    }
}

Canceling Tasks

Task.Run with CancellationToken

When using Task.Run, you can pass the CancellationToken to the task to enable cancellation.

By integrating the CancellationToken with Task.Run, you can effectively manage and cancel asynchronous tasks as required. This capability is particularly valuable when dealing with long-running or potentially unbounded asynchronous operations.

The Task.Run method provides a straightforward method for running asynchronous operations on the ThreadPool. By passing the CancellationToken to the task initiated by Task.Run, you establish a clear mechanism for cancellation. This ensures that if cancellation is requested, the task can be notified and gracefully terminate, if programmed to do so.

Example:

Here is a related code example that demonstrates the usage of CancellationToken in C#:

using System;
using System.Threading;
using System.Threading.Tasks;

class Program
{
    static async Task Main(string[] args)
    {
        CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();
        CancellationToken cancellationToken = cancellationTokenSource.Token;

        Console.WriteLine("Starting the task...");

        Task task = Task.Run(async () =>
        {
            while (!cancellationToken.IsCancellationRequested)
            {
                Console.WriteLine("Working...");
                await Task.Delay(1000);
            }

            if (cancellationToken.IsCancellationRequested)
            {
                Console.WriteLine("Task was cancelled!");
            }
        }, cancellationToken);

        await Task.Delay(5000);

        // Request cancellation after 5 seconds
        cancellationTokenSource.Cancel();

        await task;
        
        Console.WriteLine("Task completed.");
    }
}

This code example demonstrates the use of CancellationToken to stop an asynchronous task when requested. The task continuously performs work until a cancellation request is made, at which point it gracefully terminates.

Task.Factory.StartNew with CancellationToken

The Task.Factory.StartNew method in C# allows for the execution of a task on a separate thread, which can be beneficial for improving the responsiveness and performance of an application.

One notable feature of Task.Factory.StartNew is its support for cancellation by passing the CancellationToken as a parameter. This enables the graceful termination of a task if needed, enhancing the control and flexibility of asynchronous operations.

By utilizing the CancellationToken, developers can effectively manage the lifecycle of asynchronous tasks and handle scenarios where task cancellation is required. Overall, the inclusion of cancellation support in Task.Factory.StartNew adds an important dimension to the management of asynchronous operations in C#, contributing to the overall robustness of the application’s concurrency mechanisms.

Example:

using System;
using System.Threading;
using System.Threading.Tasks;

class Program
{
    static void Main()
    {
        // Create a cancellation token source
        CancellationTokenSource cts = new CancellationTokenSource();

        // Get the cancellation token
        CancellationToken token = cts.Token;

        // Start a new task and pass the token
        Task.Factory.StartNew(() => SomeTask(token), token);

        // Simulate cancellation after 3 seconds
        Thread.Sleep(3000);
        cts.Cancel();

        Console.ReadLine();
    }

    static void SomeTask(CancellationToken token)
    {
        while (!token.IsCancellationRequested)
        {
            // Task logic here
        }
    }
}

In this example, the Task.Factory.StartNew method is utilized to initiate a new task and associate it with a CancellationToken. This ensures that the task can be gracefully terminated upon the reception of a cancellation request.

Checking for Cancellation

Within your asynchronous code, periodically check if cancellation has been requested using the IsCancellationRequested property of the CancellationToken.

Example:

if (cancellationToken.IsCancellationRequested)
{
    // Perform cleanup or handle cancellation logic
}

Throwing OperationCanceledException

To gracefully exit the task, throw an OperationCanceledException when cancellation is requested.

Example:

if (cancellationToken.IsCancellationRequested)
{
    throw new OperationCanceledException(cancellationToken);
}

Handling Cancellation:

Task Cancellation Exception:

When a task is canceled, it throws a TaskCanceledException. Handle this exception to perform cleanup or log the cancellation.

Example:

try
{
    // Your asynchronous code
}
catch (TaskCanceledException ex)
{
    // Handle cancellation logic or perform cleanup
}

Aggregating Multiple Cancellation Tokens

You can aggregate multiple CancellationToken instances using CancellationTokenSource.CreateLinkedTokenSource. This allows multiple sources to contribute to the same token.

Example:

CancellationTokenSource cts1 = new CancellationTokenSource();
CancellationTokenSource cts2 = new CancellationTokenSource();

CancellationTokenSource linkedCts = CancellationTokenSource.CreateLinkedTokenSource(cts1.Token, cts2.Token);

Best Practices

Dispose of CancellationTokenSource

Ensure that you dispose of the CancellationTokenSource when it’s no longer needed to release associated resources.

Example:

using (CancellationTokenSource cancellationTokenSource = new CancellationTokenSource())
{
    // Your code
}

Document Cancellation Logic

Clearly document your cancellation logic, including where checks for cancellation occur and what actions are taken when cancellation is requested.


Conclusion:

In conclusion, it’s important to learn how to cancel tasks in C# using CancellationToken. By using CancellationToken in your asynchronous workflows, you can make your code gracefully respond to cancellation requests, which helps with efficient resource management and a better user experience.

Leave a comment