C#:如何通过 CancellationTokenSource 取消一个正在运行的 Task?

文章目录

    • 一、基本流程
    • 二、任务内部如何响应取消
    • 三、高级用法
    • 四、注意事项
    • 五、典型场景示例
    • 案例

在 C# 中,使用 CancellationTokenSource 取消 Task 的核心机制是通过传递令牌(Token)实现协作式取消。以下是具体实现方式和注意事项的总结:

一、基本流程

  1. 创建 CancellationTokenSource 实例
    这是取消操作的源头,用于生成取消令牌和控制取消逻辑。

    var cts = new CancellationTokenSource();
    
  2. 传递令牌到任务
    在启动任务时,将 cts.Token 作为参数传递给需要支持取消的方法。

    Task task = Task.Run(() => DoWork(cts.Token), cts.Token);
    
  3. 触发取消操作
    通过 Cancel() 方法或设置超时自动触发取消:

    cts.Cancel();                      // 立即取消
    cts.CancelAfter(5000);             // 5秒后自动取消
    

二、任务内部如何响应取消

  1. 轮询检查 IsCancellationRequested
    在任务代码中周期性地检查取消状态,手动终止操作:

    private void DoWork(CancellationToken token) {
        while (!token.IsCancellationRequested) {
            // 执行耗时操作
        }
    }
    
  2. 抛出 OperationCanceledException
    使用 ThrowIfCancellationRequested() 方法简化取消响应,此方法会在取消时自动抛出异常:

    private void DoWork(CancellationToken token) {
        while (true) {
            token.ThrowIfCancellationRequested();
            // 执行操作
        }
    }
    

三、高级用法

  1. 注册取消回调
    通过 Register 方法注册取消时的回调函数,用于资源清理或日志记录:

    cts.Token.Register(() => {
        Console.WriteLine("任务已取消");
    });
    
  2. 结合 Task.ContinueWith 处理后续逻辑
    任务取消后,可通过 ContinueWith 执行特定操作(如更新状态或恢复数据):

    task.ContinueWith(t => {
        if (t.IsCanceled) {
            Console.WriteLine("任务被取消");
        }
    });
    

四、注意事项

  1. 避免忘记传递 CancellationToken
    如果任务未接收令牌参数,取消操作将无法生效。

  2. 正确处理取消异常
    若使用 ThrowIfCancellationRequested,需确保任务代码能正确处理 OperationCanceledException,否则可能导致程序崩溃。

  3. 避免长时间不检查取消状态
    如果任务内部存在耗时循环或阻塞操作,需高频次检查 IsCancellationRequested,否则取消请求可能延迟生效。

五、典型场景示例

var cts = new CancellationTokenSource();
Task task = Task.Run(() => {
    while (true) {
        cts.Token.ThrowIfCancellationRequested();
        // 模拟工作
        Thread.Sleep(1000);
    }
}, cts.Token);

// 5秒后取消任务
cts.CancelAfter(5000);

通过以上方法,可以实现对任务的精确控制,提升异步程序的健壮性和响应性。更多实践案例可参考来源。

案例

以下是一个结合 CancellationTokenSource 实现任务取消的具体案例,包含完整代码和场景说明,引用自多个实践场景:

案例:模拟文件下载任务的可取消操作
场景需求

开发一个后台文件下载功能,允许用户在下载过程中随时取消,并实现以下功能:

  1. 每秒模拟下载进度更新
    2.5秒后自动取消任务(模拟超时)
  2. 取消时触发资源清理和日志记录

完整代码实现

using System;
using System.Threading;
using System.Threading.Tasks;
 
class Program 
{
    static async Task Main()
    {
        // 1. 创建取消令牌源
        var cts = new CancellationTokenSource();
        
        // 2. 注册取消回调(清理资源)
        cts.Token.Register(() => 
        {
            Console.WriteLine("\n释放网络连接资源...");
            Console.WriteLine("下载已取消");
        });
 
        try 
        {
            // 3. 启动下载任务 
            var downloadTask = DownloadFileAsync(cts.Token);
            
            // 4. 设置5秒后自动取消 
            cts.CancelAfter(5000);
            
            await downloadTask;
            Console.WriteLine("下载完成!");
        }
        catch (OperationCanceledException)
        {
            // 5. 处理取消异常 
            Console.WriteLine("\n用户主动取消下载");
        }
    }
 
    static async Task DownloadFileAsync(CancellationToken token)
    {
        try 
        {
            for (int i = 0; i <= 100; i++)
            {
                // 6. 检查取消请求 
                token.ThrowIfCancellationRequested();
                
                // 模拟下载进度 
                Console.WriteLine($"进度: {i}%");
                await Task.Delay(1000, token); // 传递令牌到延迟操作 
            }
        }
        finally 
        {
            // 7. 最终资源清理(无论是否取消)
            Console.WriteLine("清理临时文件...");
        }
    }
}

关键实现解析

  1. 双重取消检查机制

    • 通过 ThrowIfCancellationRequested() 主动抛出异常终止任务
    • Task.Delay 传递令牌参数,在等待期间响应取消
  2. 分层资源管理

    • 使用 Register 处理网络连接释放(取消时立即执行)
    • finally 块中确保临时文件清理(无论是否取消)
  3. 超时自动取消
    CancelAfter(5000) 实现无人值守场景下的安全机制

运行结果示例

进度: 0%
进度: 1%
进度: 2%
进度: 3%
进度: 4%
释放网络连接资源...
下载已取消 
清理临时文件...
用户主动取消下载 

扩展实践建议

  1. UI集成:在WPF/WinForms中可将进度更新绑定到进度条控件
  2. 重试逻辑:捕捉 OperationCanceledException 后实现自动重试机制
  3. 复合令牌:通过 CancellationTokenSource.CreateLinkedTokenSource 实现多条件取消

此案例涵盖了任务取消的核心模式,可直接应用于网络请求、大数据处理等需要中断控制的场景。

海量H5小游戏、微信小游戏、Web casualgame源码
试玩地址: https://www.bojiogame.sg
看上哪一款,需要源码的csdn私信我

————————————————

​最后我们放松一下眼睛
在这里插入图片描述

你可能感兴趣的:(c#,java,数据库)