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 分钟前
LangChain.js:Tool、Memory 与 Agent 的深度解析与实战
开发语言·javascript·langchain
吴佳浩 Alben14 分钟前
Python入门指南(六) - 搭建你的第一个YOLO检测API
开发语言·python·yolo
love530love15 分钟前
Win11+RTX3090 亲测 · ComfyUI Hunyuan3D 全程实录 ③:diso 源码编译实战(CUDA 13.1 零降级)
开发语言·人工智能·windows·python·comfyui·hunyuan3d·diso
qq_3771123716 分钟前
JAVA的平凡之路——此峰乃是最高峰JVM-GC垃圾回收器(2)-06
java·开发语言·jvm
weixin_4686352919 分钟前
用python获取双色球历史数据,纯数据处理,非爬虫
开发语言·爬虫·python
李少兄22 分钟前
深入理解 Java Web 开发中的 HttpServletRequest 与 HttpServletResponse
java·开发语言·前端
kylezhao201927 分钟前
C#变量 + 工业常用数据类型:重点 byte/int/float
开发语言·c#·c#上位机
yyy(十一月限定版)31 分钟前
c语言——二叉树
c语言·开发语言·数据结构
froginwe1135 分钟前
Web 品质国际化
开发语言
亮子AI37 分钟前
【Svelte】怎样实现一个图片上传功能?
开发语言·前端·javascript·svelte