应避免使用 Thread.Abort(),改用 CancellationToken 协作式取消;线程需主动轮询 IsCancellationRequested 或调用 ThrowIfCancellationRequested,尤其在循环、IO 和阻塞调用中高频检查,否则取消将失效。

直接终止线程会出问题,别用 Thread.Abort()
在 .NET Framework 旧项目里可能见过 Thread.Abort(),但它早在 .NET Core 起就被标记为废弃,且实际非常危险:它会在任意指令点强行中断线程,可能留下未释放的资源、死锁或对象状态不一致。现代 C# 中没有“安全终止线程”的底层操作——正确做法是让线程自己退出。
CancellationToken 不是命令,而是协作信号
它本质是一个轻量通知机制:调用方设 cancellationTokenSource.Cancel(),工作线程定期检查 cancellationToken.IsCancellationRequested 或调用 cancellationToken.ThrowIfCancellationRequested() 主动退出。关键在于“协作”二字——线程必须主动配合,否则信号完全无效。
常见错误现象:
- 只在方法开头检查一次
IsCancellationRequested,后续长循环/IO 阻塞中不再轮询 → 取消不响应 - 在
catch块里吞掉OperationCanceledException且没 rethrow → 看似取消成功,实则任务卡住 - 把
CancellationToken传进异步方法但没用await xxx.ConfigureAwait(false)或漏传 → 取消信号丢失
同步代码里怎么用 CancellationToken
适用于 CPU 密集型计算、手动轮询场景。核心是高频检查 + 及时退出,尤其注意循环和阻塞调用。
实操建议:
- 长循环内每迭代几次就检查一次
cancellationToken.IsCancellationRequested,避免响应延迟过长 - 调用可取消的 API(如
Task.Delay(1000, token)、stream.ReadAsync(buffer, token))时,务必传入token,它们内部会自动响应 - 自定义阻塞操作(如
ManualResetEvent.WaitOne())要用带 token 的重载:waitHandle.WaitOne(timeout, cancellationToken) - 不要在
finally块里再检查 token 并抛异常——此时已进入清理阶段,应专注释放资源
示例片段:
CancellationToken
- 所有
async Task方法签名必须带CancellationToken token = default参数,并在每个 await 前确保它被传入下游(如await File.ReadAllBytesAsync(path, token)) - 用
Task.Run(() => { ... }, token)启动后台任务时,token只控制任务调度,不自动注入到委托体内 —— 你仍需在委托里手动检查 - 捕获
OperationCanceledException后,除非你要做特殊清理,否则直接让它向上冒泡;若吞掉,记得调用cancellationToken.ThrowIfCancellationRequested()补检一次,防止“假取消” - .NET 6+ 支持
async Task Main(string[] args, CancellationToken token)入口参数,这是 CLI 场景下最干净的取消入口
真正难的不是写 cancellationToken.ThrowIfCancellationRequested(),而是在 IO 等待、锁竞争、回调嵌套、第三方 SDK 封装这些地方,找到所有该检查却漏了的地方。一个没覆盖的阻塞点,就足以让整个取消流程失效。











