通过在 Register 回调中调用 ThrowIfCancellationRequested 来响应取消请求

Reacting to Cancellation Request by calling ThrowIfCancellationRequested inside Register callback

我正在尝试迁移到使用 .NET 中的 CancellationToken/Src 构造,例如:https://docs.microsoft.com/en-us/dotnet/standard/threading/cancellation-in-managed-threads

我的基本问题是关于如何回应取消请求。

在我的例子中,我有一些对一致性不重要的长运行 处理。当取消请求到达时,我无法承受 "polling" 的模式,例如:

        while (!_token.IsCancellationRequested)
        {
            DoProcessing(...)
        }

因为处理可能需要几分钟时间,我真的很想现在就退出。

我的问题是,如果正确的方法是简单地使用此设置:

    public void Start()
    {
        _token.Register(() => _token.ThrowIfCancellationRequested());

        // Continuously process stuff.
        while (!_token.IsCancellationRequested)
        {
            DoProcessing(...)
        }
    }

也就是说,注册一个回调,该回调只会抛出 OperationCanceledException。

我可以在这里阅读:https://docs.microsoft.com/en-us/dotnet/api/system.threading.cancellationtokensource.cancel?view=netframework-4.8,那:

We recommend that cancelable operations and callbacks registered with CancellationToken not throw exceptions.

然而...

立即中断我的处理,而不是轮询,并且仍然遵守框架规定的 "rules" 的正确方法是什么?

我能理解这句话似乎建议不要使用 ThrowIfCancellationRequested,但事实并非如此——使用 ThrowIfCancellationRequested 是合适的。

一些来源表明使用 ThrowIfCancellationRequested 是合适的:

Jon Skeet 的 SO answer 表明 ThrowIfCancellationRequested 是正确的方法。

Throwing OperationCanceledException is the idiomatic way that "the method you called was cancelled" is expressed in TPL. Don't fight against that - just expect it.

这个Microsoft source 表明 ThrowIfCancellationRequested 是正确的方法。

A successful cancellation involves the requesting code calling the CancellationTokenSource.Cancel method, and the user delegate terminating the operation in a timely manner. You can terminate the operation by using one of these options:

  • By simply returning from the delegate [snipped remainder of this bullet]
  • By throwing a OperationCanceledException and passing it the token on which cancellation was requested. The preferred way to do this is to use the ThrowIfCancellationRequested method. A task that is canceled in this way transitions to the Canceled state, which the calling code can use to verify that the task responded to its cancellation request

还有一个代码示例演示了如何正确使用 ThrowIfCancellationRequested

进一步阅读此 Microsoft 资源的另一引述:

When a task instance observes an OperationCanceledException thrown by user code ... the task interprets this as acknowledging cancellation and transitions to the Canceled state.

...

Also note that the presence of other exceptions will also cause the Task to transition to the Faulted state ...

  • 我怀疑(这只是我试图调和这两个来源)这就是你引用的建议所指的——这是一个避免破坏取消机制准确指示任务状态的能力的建议已取消或出错