在 C# 中,使用 CancellationTokenSource
取消 Task
的核心机制是通过传递令牌(Token)实现协作式取消。以下是具体实现方式和注意事项的总结:
创建 CancellationTokenSource
实例
这是取消操作的源头,用于生成取消令牌和控制取消逻辑。
var cts = new CancellationTokenSource();
传递令牌到任务
在启动任务时,将 cts.Token
作为参数传递给需要支持取消的方法。
Task task = Task.Run(() => DoWork(cts.Token), cts.Token);
触发取消操作
通过 Cancel()
方法或设置超时自动触发取消:
cts.Cancel(); // 立即取消
cts.CancelAfter(5000); // 5秒后自动取消
轮询检查 IsCancellationRequested
在任务代码中周期性地检查取消状态,手动终止操作:
private void DoWork(CancellationToken token) {
while (!token.IsCancellationRequested) {
// 执行耗时操作
}
}
抛出 OperationCanceledException
使用 ThrowIfCancellationRequested()
方法简化取消响应,此方法会在取消时自动抛出异常:
private void DoWork(CancellationToken token) {
while (true) {
token.ThrowIfCancellationRequested();
// 执行操作
}
}
注册取消回调
通过 Register
方法注册取消时的回调函数,用于资源清理或日志记录:
cts.Token.Register(() => {
Console.WriteLine("任务已取消");
});
结合 Task.ContinueWith
处理后续逻辑
任务取消后,可通过 ContinueWith
执行特定操作(如更新状态或恢复数据):
task.ContinueWith(t => {
if (t.IsCanceled) {
Console.WriteLine("任务被取消");
}
});
避免忘记传递 CancellationToken
如果任务未接收令牌参数,取消操作将无法生效。
正确处理取消异常
若使用 ThrowIfCancellationRequested
,需确保任务代码能正确处理 OperationCanceledException
,否则可能导致程序崩溃。
避免长时间不检查取消状态
如果任务内部存在耗时循环或阻塞操作,需高频次检查 IsCancellationRequested
,否则取消请求可能延迟生效。
var cts = new CancellationTokenSource();
Task task = Task.Run(() => {
while (true) {
cts.Token.ThrowIfCancellationRequested();
// 模拟工作
Thread.Sleep(1000);
}
}, cts.Token);
// 5秒后取消任务
cts.CancelAfter(5000);
通过以上方法,可以实现对任务的精确控制,提升异步程序的健壮性和响应性。更多实践案例可参考来源。
以下是一个结合 CancellationTokenSource
实现任务取消的具体案例,包含完整代码和场景说明,引用自多个实践场景:
案例:模拟文件下载任务的可取消操作
场景需求
开发一个后台文件下载功能,允许用户在下载过程中随时取消,并实现以下功能:
完整代码实现
using System;
using System.Threading;
using System.Threading.Tasks;
class Program
{
static async Task Main()
{
// 1. 创建取消令牌源
var cts = new CancellationTokenSource();
// 2. 注册取消回调(清理资源)
cts.Token.Register(() =>
{
Console.WriteLine("\n释放网络连接资源...");
Console.WriteLine("下载已取消");
});
try
{
// 3. 启动下载任务
var downloadTask = DownloadFileAsync(cts.Token);
// 4. 设置5秒后自动取消
cts.CancelAfter(5000);
await downloadTask;
Console.WriteLine("下载完成!");
}
catch (OperationCanceledException)
{
// 5. 处理取消异常
Console.WriteLine("\n用户主动取消下载");
}
}
static async Task DownloadFileAsync(CancellationToken token)
{
try
{
for (int i = 0; i <= 100; i++)
{
// 6. 检查取消请求
token.ThrowIfCancellationRequested();
// 模拟下载进度
Console.WriteLine($"进度: {i}%");
await Task.Delay(1000, token); // 传递令牌到延迟操作
}
}
finally
{
// 7. 最终资源清理(无论是否取消)
Console.WriteLine("清理临时文件...");
}
}
}
关键实现解析
双重取消检查机制
ThrowIfCancellationRequested()
主动抛出异常终止任务Task.Delay
传递令牌参数,在等待期间响应取消分层资源管理
Register
处理网络连接释放(取消时立即执行)finally
块中确保临时文件清理(无论是否取消)超时自动取消
CancelAfter(5000)
实现无人值守场景下的安全机制
运行结果示例
进度: 0%
进度: 1%
进度: 2%
进度: 3%
进度: 4%
释放网络连接资源...
下载已取消
清理临时文件...
用户主动取消下载
扩展实践建议
OperationCanceledException
后实现自动重试机制CancellationTokenSource.CreateLinkedTokenSource
实现多条件取消此案例涵盖了任务取消的核心模式,可直接应用于网络请求、大数据处理等需要中断控制的场景。
————————————————
最后我们放松一下眼睛