CancellationToken 不适用于零超时
CancellationToken not working with zero timeout
我有一个代码依赖于零超时的取消令牌来提早退出。这是片段
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 块,但它并没有这样做。知道为什么会这样吗?另外,有什么方法可以实现我想要做的事情吗?
解释一下问题:
Why, when you create a linked CancellationTokenSource
from a
CancellationTokenSource
with a registered timeout, then set the resultant token source with a timeout of zero, does it not know it
should be cancelled?
更多释义:
After all, zero is zero and it should know it's cancelled.
答案是,因为 CancellationTokenSource.CancelAfter
试图注册一个计时器回调,它试图将分辨率设置为零毫秒,这是它不可能遵守的。
因此,在不使用 CPU 旋转的情况下,您可以获得任何标准计时机制可以为您提供的最小分辨率,大约 5+ 毫秒。
您的问题可能有其他解决方案,但是,简而言之,您不能依赖 0
第二次超时通过 IsCancellationRequested
立即确认。你需要重新考虑你的问题。
CancellationTokenSource.CancelAfter
method (source code) 不包括对 TimeSpan.Zero
值的特殊处理,因此取消计划到 ThreadPool
,Timer
超时为零。这会导致竞争条件,同步 while (!linkedCancellationTokenSource.IsCancellationRequested)
循环在大多数情况下获胜。考虑到 DoIdleWait
方法的实现不受您的控制,我能想到的唯一解决方案是,如果您知道超时为零,则不要调用此方法。
我有一个代码依赖于零超时的取消令牌来提早退出。这是片段
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 块,但它并没有这样做。知道为什么会这样吗?另外,有什么方法可以实现我想要做的事情吗?
解释一下问题:
Why, when you create a linked
CancellationTokenSource
from aCancellationTokenSource
with a registered timeout, then set the resultant token source with a timeout of zero, does it not know it should be cancelled?
更多释义:
After all, zero is zero and it should know it's cancelled.
答案是,因为 CancellationTokenSource.CancelAfter
试图注册一个计时器回调,它试图将分辨率设置为零毫秒,这是它不可能遵守的。
因此,在不使用 CPU 旋转的情况下,您可以获得任何标准计时机制可以为您提供的最小分辨率,大约 5+ 毫秒。
您的问题可能有其他解决方案,但是,简而言之,您不能依赖 0
第二次超时通过 IsCancellationRequested
立即确认。你需要重新考虑你的问题。
CancellationTokenSource.CancelAfter
method (source code) 不包括对 TimeSpan.Zero
值的特殊处理,因此取消计划到 ThreadPool
,Timer
超时为零。这会导致竞争条件,同步 while (!linkedCancellationTokenSource.IsCancellationRequested)
循环在大多数情况下获胜。考虑到 DoIdleWait
方法的实现不受您的控制,我能想到的唯一解决方案是,如果您知道超时为零,则不要调用此方法。