CancellationToken 不能使用零超时
Posted
技术标签:
【中文标题】CancellationToken 不能使用零超时【英文标题】:CancellationToken not working with zero timeout 【发布时间】:2021-12-27 05:44:29 【问题描述】:我有一个代码,它依赖于一个零超时的取消令牌来提早退出。这是sn-p
using System;
using System.Threading;
namespace ConsoleApp2
class Program
void DoIdleWait(TimeSpan timeout, CancellationToken cancellationToken)
var linkedCancellationTokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);
linkedCancellationTokenSource.CancelAfter(timeout);
while (!linkedCancellationTokenSource.IsCancellationRequested)
Console.WriteLine("Waiting");
static void Main(string[] args)
var prog = new Program();
var cts = new CancellationTokenSource();
cts.CancelAfter(TimeSpan.FromSeconds(2));
prog.DoIdleWait(TimeSpan.Zero, cts.Token);
由于超时为零,我希望它不会进入 if 块,但它没有这样做。知道为什么会这样吗?另外,有什么方法可以实现我想要做的吗?
【问题讨论】:
【参考方案1】:解释问题:
为什么,当您从一个
CancellationTokenSource
注册了 timeout,然后将生成的 token source 设置为 timeout 为零,它不知道吗 应该取消吗?
更多解释:
毕竟,零就是零,它应该知道它被取消了。
答案是,因为CancellationTokenSource.CancelAfter
试图注册一个计时器回调,它试图将分辨率设置为零毫秒,这是它不可能遵守的。
因此,您可以在不使用 CPU 旋转的情况下获得任何标准计时机制所能提供的最低分辨率,大约为 5 毫秒以上。
您的问题可能还有其他解决方案,但是,简而言之,您不能依靠0
第二次超时来通过IsCancellationRequested
立即确认。你需要重新考虑你的问题。
【讨论】:
感谢您的全面回答。检查取消令牌的代码由另一方拥有,这就是为什么我试图通过通过零超时来提前退出。我会尝试重新考虑这个问题,因为那行不通。【参考方案2】:CancellationTokenSource.CancelAfter
方法 (source code) 不包括对 TimeSpan.Zero
值的特殊处理,因此将取消安排到 ThreadPool
与 Timer
具有零超时。这会导致竞争条件,同步while (!linkedCancellationTokenSource.IsCancellationRequested)
循环在大多数情况下都会获胜。考虑到DoIdleWait
方法的实现不受您的控制,我能想到的唯一解决方案是,如果您知道超时为零,则不要调用此方法。
【讨论】:
以上是关于CancellationToken 不能使用零超时的主要内容,如果未能解决你的问题,请参考以下文章
具有CancellationToken和ReadTimeout的异步串行端口
我应该如何使用 DataflowBlockOptions.CancellationToken?
C#:使用 CancellationToken 取消 MySqlCommand,给出 NULLReferenceException