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)
实现自动取消。
这种方法适用于 Task
、async/await
、Parallel.ForEach
等场景,是 .NET 中处理任务取消的标准模式。