是否有必要在处置前取消cancellationtoken

is it necessary to cancel cancellationtoken before disposal

我大部分时间都使用 CancellationTokenSource 来超时。为避免忘记 dispose,当我完成 CancellationTokenSource 时,我使用了 using 语句。但是在 using 语句结束之前,我总是在做一个 CancellationTokenSource.Cancel().

未使用过的注销是否需要注销CancellationTokenSource后才能处理?

这是我执行此操作的代码示例。

using (CancellationTokenSource TokenSource = new CancellationTokenSource(nTimeout * 1000))
{
  for (int i = 0; i < nLoop; i++)
  {
    if (TokenSource.Token.IsCancellationRequested)
    {
      bSuccess = false;
      break;
    }

    await Task.Delay(cDelay);
    // do some work
  }

  TokenSource.Cancel();
}

在处理 CancellationTokenSource 之后,基于此来源的令牌可能会抛出 ObjectDisposedException,因此您不应在处理该来源后使用 CancellationTokenSource.Token。幸运的是,我没有在您的代码中看到这种情况。

当您取消 CancellationTokenSource 时,它会更改状态并通知已为令牌注册的回调。但是,当您的代码即将处理 CancellationTokenSource 时,您已经完成了对令牌的使用,无需取消它。

因此,在您的情况下,没有必要在处理之前取消 CancellationTokenSource。但是,您的用例有些特殊。当你有一个后台任务时,你应该在处理源之前等待任务完成(如我开头段落中所述):

using (var cts = new CancellationTokenSource()) {
    var task = Task.Run(() => DoSomething(cts.Token));
    // Cancel cts or let it cancel itself based on a timeout.
    // Then wait for the task to end.
    await task;
}

对于“CancellationTokenSource销毁前是否需要注销?”的问题答案是否定的,没有必要。 但取消与否决定了孤儿令牌的最终状态。

作为一般规则,在处置其来源后不应使用孤立令牌。但是,如果您对尝试使用它会发生什么感到好奇,那么它应该在某种程度上起作用。例如检查这个测试:

[Theory]
[InlineData(false)]
[InlineData(true)]
public void Test48538934(bool canceledBeforeDispose)
{
    var cts = new CancellationTokenSource();
    var ct = cts.Token;

    Assert.False(cts.IsCancellationRequested);
    Assert.False(ct.IsCancellationRequested);

    if (canceledBeforeDispose)
        cts.Cancel();

    Assert.Equal(canceledBeforeDispose, cts.IsCancellationRequested);
    Assert.Equal(canceledBeforeDispose, ct.IsCancellationRequested);

    cts.Dispose();

    Assert.Throws<ObjectDisposedException>(() => cts.Token);

    Assert.Equal(canceledBeforeDispose, cts.IsCancellationRequested);
    Assert.Equal(canceledBeforeDispose, ct.IsCancellationRequested);
}

因此,如果令牌在异步调用管道中的某处意外丢失,可能需要在处理它之前取消源。