CancellationToken设置零超时未生效的原因及实现提前退出的方法
问题产生原因
该问题的根源是CancellationTokenSource.CancelAfter()的取消触发逻辑是异步的,而非同步执行:
- 即便传入
TimeSpan.Zero作为超时时间,CancelAfter内部也是通过线程池定时器触发取消操作,取消信号的设置会存在极短的线程调度延迟 - 调用CancelAfter之后立即判断
IsCancellationRequested属性时,定时器回调还没来得及执行,取消标志还未被置为true,因此程序会直接进入while循环,不符合预期。
实现提前退出的方案
最稳妥的方式是主动判断超时时间,同步触发取消,避免依赖异步的定时器调度,修改后的DoIdleWait方法代码如下:
void DoIdleWait(TimeSpan timeout, CancellationToken cancellationToken) { var linkedCancellationTokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken); // 新增判断:如果超时时间小于等于0,直接同步触发取消,不需要走异步定时器 if (timeout <= TimeSpan.Zero) { linkedCancellationTokenSource.Cancel(); } else { linkedCancellationTokenSource.CancelAfter(timeout); } while (!linkedCancellationTokenSource.IsCancellationRequested) { Console.WriteLine("Waiting"); } // 新增资源释放,避免非托管资源泄漏 linkedCancellationTokenSource.Dispose(); }
该修改是同步设置取消标志,不需要等待线程池调度,调用Cancel后立即就能检测到IsCancellationRequested为true,不会进入while循环,完全符合预期。
内容的提问来源于stack exchange,提问作者seaofpuppies
相关产品推荐
相关产品推荐

