【问题标题】:Is code that disposes CancellationTokenSource while tasks are canceling correct?在任务取消时处理 CancellationTokenSource 的代码是否正确?
【发布时间】:2015-04-21 18:02:01
【问题描述】:

我看到眼前的这段代码,我很怀疑:

CancellationTokenSource _cts;

public void Dispose();
{
    _cts.Cancel();
    _cts.Dispose();
    _task.Wait(); //wait for the task to be canceled!?
}

取消后直接调用 _cts.Dispose() 是否安全?如果它想这样做,那是否会处理被取消的任务成功等待 CancellationToken 所需的 CancellationTokenSource 的底层资源?

【问题讨论】:

    标签: c# .net cancellationtokensource


    【解决方案1】:

    取消后直接调用 _cts.Dispose() 是否安全?

    为了知道这一点,我们需要了解当我们取消 CancellationTokenSource 时会发生什么。

    当您取消 CancellationTokenSource 时,它会继续调用通过 CancellationToken 注册的任何回调,该回调通过 CancellationToken.Register() 方法保存对其父源的引用。

    当您处置 CTS 时,任何已注册的链接回调都会尝试从令牌中注销。如果它当前正在执行,它将等到它的委托完成。

    这意味着,尽管您已处置 CTS,但它的对象仍被令牌引用。因此,它仍然不符合收集条件。

    现在让我们看看CancellationToken.IsCancellationRequested

    public bool IsCancellationRequested 
    {
        get
        {
            return m_source != null && m_source.IsCancellationRequested;
        }
    }
    

    这意味着在处置时,检查取消将产生 true。这意味着,调用 dispose 后等待任务完成是安全的。

    附带说明,如果您(出于某种原因)尝试通过已处置的CancellationTokenSource 传递令牌,您将遇到ObjectDisposedException

    编辑:

    我想补充两点。首先,让我说我不建议使用这种方法。它应该适用于某些代码执行路径,但不适用于所有路径。 CancellationTokenSource 通常只有在你使用它的 WaitHandle 属性时才应该被释放。否则,最好让 GC 进行清理。但是,因为这是一个口味问题,你可以选择任何你喜欢的。我当然会建议您仅在您确定任务已观察到取消请求后才进行处理。

    按照WaitHandle的用法,一旦你dispose它就会被dispose并清空,所以它不会被访问到。

    【讨论】:

    • 但是 IsCancellationRequested 并不是唯一需要担心的情​​况,对吧? WaitHandle 呢?
    • 如果 dispose 运行,WaitHandle 将被关闭。我不确定使用WaitHandle 是一个常见的用例。我会把它添加到我的答案中。
    • @Tim 我在我的答案中添加了一个重要的编辑。尽管您尝试做的是可能,但我当然不会推荐它。
    猜你喜欢
    • 1970-01-01
    • 2020-02-25
    • 1970-01-01
    • 2016-08-26
    • 2015-03-20
    • 2019-07-27
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多