16、取消线程
取消线程
知识点概述
线程取消是多线程编程中的重要概念,用于优雅地停止正在执行的线程。.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是取消操作的标准异常
- 性能考虑: 适当的取消检查频率平衡响应性和性能

浙公网安备 33010602011771号