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