
在多线程编程、异步操作场景下,难免会遇到需要提前终止操作的情况。比如用户在下载过程中突然取消,或者一个任务执行时间过长需要强制停止。CancellationToken正是为优雅地处理这些情况而生,深入理解它有助于开发者编写健壮、高效且响应灵敏的应用程序。
CancellationToken不会强制终止任务,而是提供一种机制,让任务有机会在合适的时机优雅地停止。CancellationTokenSource类用于创建CancellationToken实例,并提供取消操作的方法。public class CancellationTokenSource : IDisposable
{
private CancellationTokenRegistration _parentRegistration;
private CancellationTokenRegistration _disposeRegistration;
private volatile int _state;
// 省略其他代码
public void Cancel()
{
Cancel(false);
}
private void Cancel(bool throwOnFirstException)
{
if (Interlocked.CompareExchange(ref _state, (int)CancellationTokenSourceState.Canceled, (int)CancellationTokenSourceState.Created) != (int)CancellationTokenSourceState.Created)
{
return;
}
// 触发取消通知
// 省略通知相关代码
}
}CancellationTokenSource通过内部状态变量_state来跟踪状态。Cancel方法首先使用Interlocked.CompareExchange原子操作尝试将状态从Created改为Canceled,如果成功则触发取消通知。CancellationToken取消一个简单的异步任务。using System;
using System.Threading;
using System.Threading.Tasks;
class Program
{
static async Task Main()
{
var cts = new CancellationTokenSource();
CancellationToken token = cts.Token;
Task task = Task.Run(() => DoWork(token), token);
// 模拟其他操作
await Task.Delay(2000);
// 取消任务
cts.Cancel();
try
{
await task;
}
catch (OperationCanceledException)
{
Console.WriteLine("任务已取消");
}
}
static void DoWork(CancellationToken token)
{
while (!token.IsCancellationRequested)
{
Console.WriteLine("工作进行中...");
Task.Delay(500).Wait();
}
Console.WriteLine("收到取消请求,停止工作");
}
}CancellationTokenSource创建CancellationToken。DoWork方法通过token.IsCancellationRequested检查是否收到取消请求。主线程在适当时候调用cts.Cancel()发出取消信号,try - catch块捕获OperationCanceledException。using System;
using System.Threading;
using System.Threading.Tasks;
class Program
{
static async Task Main()
{
using (var cts = new CancellationTokenSource(TimeSpan.FromSeconds(3)))
{
CancellationToken token = cts.Token;
Task task = Task.Run(() => LongRunningWork(token), token);
try
{
await task;
}
catch (OperationCanceledException)
{
Console.WriteLine("任务超时被取消");
}
}
}
static void LongRunningWork(CancellationToken token)
{
for (int i = 0; i < 10; i++)
{
if (token.IsCancellationRequested)
{
Console.WriteLine("收到取消请求,停止工作");
return;
}
Console.WriteLine($"工作步骤 {i}");
Task.Delay(1000).Wait();
}
}
}CancellationTokenSource构造函数中设置了3秒的超时时间。LongRunningWork方法在每次循环中检查取消请求,若收到则停止工作。CancellationToken,导致无法响应取消请求。using System;
using System.Threading;
using System.Threading.Tasks;
class Program
{
static async Task Main()
{
var cts = new CancellationTokenSource();
CancellationToken token = cts.Token;
Task task = Task.Run(() => IncorrectAsyncWork());
await Task.Delay(2000);
cts.Cancel();
try
{
await task;
}
catch (OperationCanceledException)
{
Console.WriteLine("任务已取消");
}
}
static async Task IncorrectAsyncWork()
{
// 未检查CancellationToken
await Task.Delay(5000);
Console.WriteLine("任务完成(但未响应取消)");
}
}CancellationToken。using System;
using System.Threading;
using System.Threading.Tasks;
class Program
{
static async Task Main()
{
var cts = new CancellationTokenSource();
CancellationToken token = cts.Token;
Task task = Task.Run(() => CorrectAsyncWork(token), token);
await Task.Delay(2000);
cts.Cancel();
try
{
await task;
}
catch (OperationCanceledException)
{
Console.WriteLine("任务已取消");
}
}
static async Task CorrectAsyncWork(CancellationToken token)
{
await Task.Delay(TimeSpan.FromSeconds(5), token);
Console.WriteLine("任务完成(已响应取消)");
}
}CorrectAsyncWork方法在Task.Delay中传递CancellationToken,使其能够响应取消请求。CancellationToken本身的开销极小,主要性能影响在于任务检查取消请求的频率。过于频繁检查可能增加额外开销,而检查过少可能导致响应取消不及时。CancellationToken,避免遗漏。OperationCanceledException时,应做好资源清理等善后工作。CancellationToken时,任何一个任务收到取消信号都会取消所有相关任务,适合需要整体取消的场景。token.Register注册回调方法,在取消时执行相应逻辑。CancellationToken为.NET开发者提供了一种优雅、高效的取消机制。核心要点在于协作式取消的理解和正确使用方式。适用于任何需要控制任务生命周期的场景,但不适合用于立即强制终止任务。随着.NET发展,预计会进一步优化取消机制在复杂场景下的易用性和性能。