Parallel.ForEach循环中Cancellation Token无法生效问题求助
解决CTRL-C无法终止Parallel.ForEach任务的问题
你的代码存在几个关键问题导致无法响应CTRL-C的取消请求,具体问题和修复方案如下:
事件注册时机错误
你在调用StartAllReaders之后才绑定Console.CancelKeyPress事件,这意味着如果用户在任务启动后立刻按下CTRL-C,事件还未生效,无法触发取消操作。必须先注册事件,再启动任务。Thread.Sleep阻塞导致取消信号无法及时响应
Thread.Sleep是不支持取消的阻塞操作,一旦进入休眠状态,即使取消令牌被触发,也要等到休眠结束才能检查取消请求。需要替换为支持取消的等待方式,让休眠过程也能响应取消信号。取消异常处理逻辑不完善
循环内的异常捕获会吃掉所有异常,包括取消操作抛出的OperationCanceledException,导致循环无法及时退出。需要单独捕获取消异常,直接终止循环。语法错误
代码存在几处大小写和语法问题:cts.cancel()应改为cts.Cancel(),e.cancel = true应改为e.Cancel = true,StartAllReaders(cts.token)末尾缺少分号。
修正后的代码
public static void Main(string[] args) { CancellationTokenSource cts = new CancellationTokenSource(); // 先注册取消事件,确保任何时候按下CTRL-C都能触发 Console.CancelKeyPress += (s, e) => { cts.Cancel(); e.Cancel = true; // 阻止系统直接终止进程,让代码完成清理操作 }; StartAllReaders(cts.Token); } public static void StartAllReaders(CancellationToken cts) { try { Parallel.ForEach( _readers, new ParallelOptions { MaxDegreeOfParallelism = 10, CancellationToken = cts }, (reader, state) => { reader.Start(); while (!cts.IsCancellationRequested) { try { reader.ReadTelemetry(); // 用支持取消的Task.Delay替代Thread.Sleep,响应取消信号 Task.Delay(reader.TimeDelay, cts).Wait(); } catch (OperationCanceledException) { // 捕获取消异常,直接退出循环 break; } catch (Exception ex) { // 记录异常日志 continue; } } // 可选:添加reader的停止清理逻辑,比如reader.Stop() }); } catch (OperationCanceledException) { Logger.Info("Readers are stopping."); } }
内容的提问来源于stack exchange,提问作者Kristielingg
相关产品推荐
相关产品推荐

