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

相关推荐
我材不敲代码3 小时前
Python实现打包贪吃蛇游戏
开发语言·python·游戏
身如柳絮随风扬4 小时前
Java中的CAS机制详解
java·开发语言
韩立学长6 小时前
【开题答辩实录分享】以《基于Python的大学超市仓储信息管理系统的设计与实现》为例进行选题答辩实录分享
开发语言·python
froginwe116 小时前
Scala 循环
开发语言
m0_706653236 小时前
C++编译期数组操作
开发语言·c++·算法
故事和你917 小时前
sdut-Java面向对象-06 继承和多态、抽象类和接口(函数题:10-18题)
java·开发语言·算法·面向对象·基础语法·继承和多态·抽象类和接口
Bruk.Liu7 小时前
(LangChain实战2):LangChain消息(message)的使用
开发语言·langchain
qq_423233907 小时前
C++与Python混合编程实战
开发语言·c++·算法
m0_715575347 小时前
分布式任务调度系统
开发语言·c++·算法
PfCoder7 小时前
C#中定时器之System.Timers.Timer
c#·.net·visual studio·winform