C# CancellationToken 终止操作

发布于:2024-12-06 ⋅ 阅读:(96) ⋅ 点赞:(0)

需要在异步操作中提供终止功能时,最常用的方法是使用 CancellationToken。这个工具可以让你在需要时优雅地取消异步操作,而不是强制终止线程。

.NET 中不建议直接终止线程,因为这可能导致资源泄露和数据不一致等问题。强制终止线程可能会中断一个正在执行的操作,甚至可能使应用程序处于未定义的状态。

1. 什么是 CancellationToken

CancellationToken 是 .NET 提供的一个结构,用于处理异步任务的取消。它允许你在长时间运行的操作中检查用户是否请求取消,从而保证程序的响应性。

2. 使用 CancellationToken 的基本步骤

以下是使用 CancellationToken 的关键步骤,这些步骤在示例代码中都有体现:

步骤 1:创建 CancellationTokenSource

首先,创建一个 CancellationTokenSource 实例。这个实例提供了一个 CancellationToken,可以将其传递给异步方法。

static CancellationTokenSource cts = new CancellationTokenSource();

步骤 2:获取 CancellationToken

通过 CancellationTokenSource 获取一个 CancellationToken,这个令牌将用于检查取消请求。

var token = cts.Token;

步骤 3:传递 CancellationToken 给异步方法

在定义的异步方法中,接受 CancellationToken 参数,并在适当的位置检查它的状态。

static async Task LongRunningOperation(CancellationToken token)
{
    for (int i = 0; i < 100; i++)
    {
        token.ThrowIfCancellationRequested(); // 检查是否请求取消
        
        // 模拟耗时操作
        Console.WriteLine($"处理第 {i + 1} 项...");
        await Task.Delay(100); // 代替耗时的操作
    }
}

在循环中,我们调用 token.ThrowIfCancellationRequested() 方法。如果调用此方法时取消请求已经发出,则会抛出 OperationCanceledException,从而允许我们在主方法中捕获并处理。

 

步骤 4:请求取消

在用户按下某个键(例如 'c' 键)时,你可以请求取消操作。这通过调用 CancellationTokenSource.Cancel 方法来实现。

if (Console.ReadKey().KeyChar == 'c')
{
    cts.Cancel(); // 请求取消
}

步骤 5:处理取消

在主方法中,通过 try-catch 块捕获 OperationCanceledException,以便在操作被取消时进行适当处理。

try
{
    await processingTask; // 等待任务完成
}
catch (OperationCanceledException)
{
    Console.WriteLine("操作已被取消。");
}

完整代码

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

class Program
{
    static CancellationTokenSource cts = new CancellationTokenSource();

    static async Task Main(string[] args)
    {
        Console.WriteLine("按下任意键开始长时间操作...");
        Console.ReadKey();

        var processingTask = LongRunningOperation(cts.Token);

        Console.WriteLine("按下 'c' 键取消操作...");
        if (Console.ReadKey().KeyChar == 'c')
        {
            cts.Cancel(); // 请求取消
        }

        try
        {
            await processingTask; // 等待任务完成
            Console.WriteLine("操作完成。");
        }
        catch (OperationCanceledException)
        {
            Console.WriteLine("操作已被取消。");
        }
        finally
        {
            cts.Dispose();
        }
    }

    static async Task LongRunningOperation(CancellationToken token)
    {
        for (int i = 0; i < 100; i++)
        {
            token.ThrowIfCancellationRequested(); // 检查是否请求取消
            
            // 模拟耗时操作
            Console.WriteLine($"处理第 {i + 1} 项...");
            await Task.Delay(100); // 代替耗时的操作
        }
    }
}


网站公告

今日签到

点亮在社区的每一天
去签到