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 中处理任务取消的标准模式。

相关推荐
鸿芯微控科技12 分钟前
压电点胶阀出胶量不稳定怎么排查?驱动波形、背压、点胶重量与Python分析
开发语言·python·压电点胶阀·精密点胶·点胶重量·流体控制
原野池予23 分钟前
深入Java集合框架:HashMap源码解析(JDK 8)
java·开发语言
测试运维日常笔记34 分钟前
VMware vSphere、ESXi 与 vCenter Server:核心概念与关系详解
java·开发语言
m0_547486661 小时前
《面向对象与Java程序设计》全套PPT课件2026
java·开发语言
星恒随风1 小时前
C++ 红黑树封装(二):迭代器、const_iterator 与 operator[] 完整实现 mymap 和 myset
开发语言·c++·状态模式
jason成都1 小时前
ignav-next|Java 层封装 GNSS/INS 组合导航框架,隔离 RTKLIB 与 INS 内核,双模块独立演进、最小侵入
java·开发语言
抓不住时间的沙1 小时前
butterfly主题美化,打造属于自己的个性博客
java·开发语言·前端·javascript·node.js·github
MarkHD1 小时前
Stable Diffusion入门第19-20天:保存与分享你的工作流——第一阶段收官,从“能用”到“可复用”
java·开发语言·stable diffusion
云水初2 小时前
【agent篇】RAG 知识库构建避坑指南
开发语言·python·学习·agent·rag
2019一路前行2 小时前
Python 函数、循环语句
开发语言·python