C#如何正确的停止一个多线程Task?CancellationTokenSource 的用法。

在 C# 中停止一个 Task 需要谨慎处理,因为直接强制终止(如 Thread.Abort())会导致资源泄漏或状态不一致。推荐使用 ​​协作式取消(Cooperative Cancellation)​ ​ 通过 CancellationToken 实现安全停止。以下是详细方法:


​1. 使用 CancellationToken 取消 Task​

​(1) 创建 CancellationTokenSource​
复制代码

csharp

复制代码
var cts = new CancellationTokenSource();
CancellationToken token = cts.Token;
​(2) 在 Task 中检查取消请求​
复制代码

csharp

复制代码
Task longRunningTask = Task.Run(() =>
{
    while (true)
    {
        // 检查是否被取消
        if (token.IsCancellationRequested)
        {
            Console.WriteLine("Task 已取消");
            token.ThrowIfCancellationRequested(); // 抛出 OperationCanceledException
        }

        // 模拟工作
        Console.WriteLine("Working...");
        Thread.Sleep(1000);
    }
}, token);
​(3) 触发取消​
复制代码

csharp

复制代码
// 请求取消
cts.Cancel();

// 可选:等待Task处理取消(避免资源泄漏)
try
{
    await longRunningTask;
}
catch (OperationCanceledException)
{
    Console.WriteLine("Task 已安全终止");
}

​2. 处理取消时的清理工作​

如果 Task 需要在取消时释放资源(如关闭文件、数据库连接),通过 finally 块或 Register 方法实现:

复制代码

csharp

复制代码
Task.Run(() =>
{
    using (var resource = new SomeDisposableResource())
    {
        try
        {
            while (!token.IsCancellationRequested)
            {
                // 工作代码
            }
        }
        finally
        {
            Console.WriteLine("释放资源");
        }
    }
}, token);

或通过 CancellationToken.Register

复制代码

csharp

复制代码
token.Register(() =>
{
    Console.WriteLine("取消时执行清理");
});

​3. 超时自动取消​

复制代码

csharp

复制代码
// 设置 5秒超时
var cts = new CancellationTokenSource(TimeSpan.FromSeconds(5));
Task.Run(() => { /* ... */ }, cts.Token);

​4. 为什么不推荐强制终止 Task?​

  • Thread.Abort() / Task.Dispose()

    • ❌ 抛出 ThreadAbortException,可能导致锁未释放、文件未关闭等问题。
    • ❌ .NET Core 及以上版本已移除 Thread.Abort()
  • ​协作式取消的优势​

    • ✅ 安全:Task 有机会清理资源。
    • ✅ 可控:可通过异常捕获取消逻辑。

​5. 完整示例​

复制代码

csharp

复制代码
using System;
using System.Threading;
using System.Threading.Tasks;

class Program
{
    static async Task Main()
    {
        var cts = new CancellationTokenSource();
        var token = cts.Token;

        Task task = Task.Run(() =>
        {
            try
            {
                while (true)
                {
                    token.ThrowIfCancellationRequested();
                    Console.WriteLine("Working...");
                    Thread.Sleep(1000);
                }
            }
            catch (OperationCanceledException)
            {
                Console.WriteLine("任务已取消");
            }
        }, token);

        // 3秒后取消
        Thread.Sleep(3000);
        cts.Cancel();

        await task; // 等待任务处理取消
    }
}

​总结​

  • ​推荐方式​ :始终通过 CancellationToken 实现协作式取消。
  • ​强制终止​:仅在极端情况下考虑,并确保资源释放。
  • ​超时控制​ :结合 CancellationTokenSource(TimeSpan) 实现自动取消。

这种方法适用于 Taskasync/awaitParallel.ForEach 等场景,是 .NET 中处理任务取消的标准模式。

相关推荐
淋一遍下雨天5 分钟前
Spark Streaming核心编程总结(四)
java·开发语言·数据库
小白学大数据12 分钟前
如何避免爬虫因Cookie过期导致登录失效
开发语言·爬虫·python·scrapy
爱吃烤鸡翅的酸菜鱼1 小时前
【SpringMVC】概念引入与连接
java·开发语言·mysql
小白学大数据1 小时前
Python自动化解决滑块验证码的最佳实践
开发语言·python·自动化
碎梦归途1 小时前
23种设计模式-行为型模式之策略模式(Java版本)
java·开发语言·jvm·设计模式·策略模式·行为型模式
Albert Edison1 小时前
Python入门基础
开发语言·python
小余吃大鱼1 小时前
OpenStack私有云详细介绍
开发语言·php·openstack
画个大饼1 小时前
Swift:什么是Optional?其背后的机制是什么?什么是Unconditional Unwrapping?
开发语言·ios·swift
T0uken1 小时前
【Python】Matplotlib:立体永生花绘制
开发语言·python·matplotlib
sniper_fandc1 小时前
JVM(Java虚拟机)详解
java·开发语言·jvm