取消线程
知识点概述
线程取消是多线程编程中的重要概念,用于优雅地停止正在执行的线程。.NET提供了多种取消线程的方式:
- CancellationToken: 现代推荐的取消机制(.NET 4.0+)
 - Thread.Abort(): 强制终止线程(已过时,不推荐)
 - Thread.Interrupt(): 中断等待中的线程
 - 共享标志位: 使用bool变量控制线程退出
 - ManualResetEvent: 基于事件的取消机制
 
代码案例
案例1:使用CancellationToken取消线程(推荐方式)
using System;
using System.Threading;
using System.Threading.Tasks;class CancellationTokenDemo
{static async Task Main(){CancellationTokenSource cts = new CancellationTokenSource();// 启动可取消的任务Task longRunningTask = LongRunningOperationAsync(cts.Token);Console.WriteLine("任务已启动,按任意键取消...");Console.ReadKey();// 请求取消cts.Cancel();try{await longRunningTask;Console.WriteLine("任务正常完成");}catch (OperationCanceledException){Console.WriteLine("任务已取消");}cts.Dispose();}static async Task LongRunningOperationAsync(CancellationToken cancellationToken){for (int i = 0; i < 100; i++){// 检查取消请求cancellationToken.ThrowIfCancellationRequested();Console.WriteLine($"处理项目 {i + 1}/100");await Task.Delay(200, cancellationToken);}Console.WriteLine("操作完成");}
}
案例2:超时自动取消
using System;
using System.Threading;
using System.Threading.Tasks;class TimeoutCancellationDemo
{static async Task Main(){// 设置5秒超时using (CancellationTokenSource cts = new CancellationTokenSource(TimeSpan.FromSeconds(5))){try{await SimulateWorkAsync(cts.Token);Console.WriteLine("工作在超时前完成");}catch (OperationCanceledException){Console.WriteLine("工作因超时被取消");}}Console.WriteLine("\n演示手动取消与超时的组合:");await CombinedCancellationDemo();}static async Task SimulateWorkAsync(CancellationToken cancellationToken){for (int i = 0; i < 30; i++){cancellationToken.ThrowIfCancellationRequested();Console.WriteLine($"工作进度: {i + 1}/30");await Task.Delay(300, cancellationToken);}}static async Task CombinedCancellationDemo(){using (CancellationTokenSource timeoutCts = new CancellationTokenSource(TimeSpan.FromSeconds(3)))using (CancellationTokenSource manualCts = new CancellationTokenSource()){// 组合超时取消和手动取消using (CancellationTokenSource combinedCts = CancellationTokenSource.CreateLinkedTokenSource(timeoutCts.Token, manualCts.Token)){Task workTask = SimulateWorkAsync(combinedCts.Token);// 模拟2秒后手动取消_ = Task.Run(async () =>{await Task.Delay(2000);manualCts.Cancel();Console.WriteLine("手动取消请求已发送");});try{await workTask;}catch (OperationCanceledException){if (timeoutCts.Token.IsCancellationRequested)Console.WriteLine("因超时取消");else if (manualCts.Token.IsCancellationRequested)Console.WriteLine("因手动请求取消");}}}}
}
案例3:使用共享标志位取消线程
using System;
using System.Threading;class FlagBasedCancellation
{private static volatile bool _shouldStop = false;static void Main(){Thread workerThread = new Thread(DoWork);workerThread.Start();Console.WriteLine("线程已启动,按任意键停止...");Console.ReadKey();// 设置停止标志_shouldStop = true;// 等待线程完成workerThread.Join();Console.WriteLine("线程已停止");}static void DoWork(){int counter = 0;while (!_shouldStop){Console.WriteLine($"工作中... {++counter}");Thread.Sleep(500);}Console.WriteLine($"线程收到停止信号,共执行了 {counter} 次操作");}
}
案例4:使用Thread.Interrupt中断等待
using System;
using System.Threading;class ThreadInterruptDemo
{static void Main(){Thread workerThread = new Thread(WaitingWork);workerThread.Start();Console.WriteLine("线程正在等待,3秒后中断...");Thread.Sleep(3000);// 中断线程workerThread.Interrupt();workerThread.Join();Console.WriteLine("程序结束");}static void WaitingWork(){try{Console.WriteLine("开始长时间等待...");Thread.Sleep(10000); // 等待10秒Console.WriteLine("等待完成");}catch (ThreadInterruptedException){Console.WriteLine("等待被中断,开始清理工作...");// 执行清理工作Thread.Sleep(1000);Console.WriteLine("清理完成");}}
}
案例5:优雅的取消处理和资源清理
using System;
using System.Threading;
using System.Threading.Tasks;
using System.IO;class GracefulCancellationDemo
{static async Task Main(){using (CancellationTokenSource cts = new CancellationTokenSource()){// 设置取消回调cts.Token.Register(() => Console.WriteLine("取消操作已触发"));Task processTask = ProcessFilesAsync(cts.Token);Console.WriteLine("文件处理已开始,按任意键取消...");Console.ReadKey();cts.Cancel();try{await processTask;}catch (OperationCanceledException){Console.WriteLine("文件处理被取消");}}}static async Task ProcessFilesAsync(CancellationToken cancellationToken){try{for (int i = 1; i <= 10; i++){using (cancellationToken.Register(() => Console.WriteLine($"正在取消文件 {i} 的处理..."))){await ProcessSingleFileAsync(i, cancellationToken);}}}catch (OperationCanceledException){Console.WriteLine("开始清理已处理的文件...");await CleanupAsync();throw; // 重新抛出以通知调用者}}static async Task ProcessSingleFileAsync(int fileNumber, CancellationToken cancellationToken){Console.WriteLine($"开始处理文件 {fileNumber}");// 模拟文件处理,支持取消for (int step = 1; step <= 5; step++){cancellationToken.ThrowIfCancellationRequested();Console.WriteLine($"  文件 {fileNumber} - 步骤 {step}/5");await Task.Delay(800, cancellationToken);}Console.WriteLine($"文件 {fileNumber} 处理完成");}static async Task CleanupAsync(){Console.WriteLine("执行清理操作...");await Task.Delay(1000); // 模拟清理时间Console.WriteLine("清理完成");}
}
案例6:多线程取消协调
using System;
using System.Threading;
using System.Threading.Tasks;
using System.Collections.Generic;class MultiThreadCancellationDemo
{static async Task Main(){using (CancellationTokenSource cts = new CancellationTokenSource()){// 启动多个工作任务List<Task> tasks = new List<Task>();for (int i = 1; i <= 3; i++){int workerId = i;tasks.Add(WorkerTaskAsync(workerId, cts.Token));}Console.WriteLine("所有工作线程已启动,按任意键取消所有任务...");Console.ReadKey();Console.WriteLine("发送取消信号...");cts.Cancel();// 等待所有任务响应取消try{await Task.WhenAll(tasks);}catch (OperationCanceledException){Console.WriteLine("所有任务已取消");}}}static async Task WorkerTaskAsync(int workerId, CancellationToken cancellationToken){try{while (true){cancellationToken.ThrowIfCancellationRequested();Console.WriteLine($"工作线程 {workerId} 正在执行...");await Task.Delay(1000, cancellationToken);}}catch (OperationCanceledException){Console.WriteLine($"工作线程 {workerId} 收到取消信号,正在清理...");// 模拟清理工作await Task.Delay(500);Console.WriteLine($"工作线程 {workerId} 清理完成");throw;}}
}
知识点总结
- CancellationToken: 现代.NET推荐的取消机制,提供协作式取消
 - 超时取消: 可以设置自动超时,避免长时间运行的任务
 - 组合取消: 可以组合多个取消源,灵活控制取消条件
 - 协作式取消: 线程需要主动检查取消标记,不是强制终止
 - 资源清理: 取消时要确保正确清理资源,避免内存泄漏
 - 异常处理: OperationCanceledException是取消操作的标准异常
 - 性能考虑: 适当的取消检查频率平衡响应性和性能
 
