问题 是否在任务取消正确时处理CancellationTokenSource的代码?


我在我面前看到这个代码,我很怀疑:

CancellationTokenSource _cts;

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

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


8525
2018-04-21 18:02


起源



答案:


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

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

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

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

这意味着,虽然你已经处理了你的CTS,它的对象仍然被令牌引用。因此,它仍然没有资格收集。

现在让我们来看看 CancellationToken.IsCancellationRequested

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

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

作为旁注,如果您(由于某种原因)尝试通过它的处置CancellationTokenSource传递令牌,您将会遇到 ObjectDisposedException

编辑:

我要添加两件事。首先,我要说我不建议使用这种方法。它应该适用于某些代码执行路径,但不适用于所有代码。 CancellationTokenSource 通常只有在你使用时才能处理 WaitHandle 属性。否则,可以将其留在GC进行清洁。但是,因为这是一个风味问题,你可以选择你喜欢的。我肯定会建议您在确定任务已经遵守取消请求后才进行处置。

根据用途 WaitHandle一旦你处理掉它,它就会被处理掉 将不会 可以到达。


11
2018-04-21 20:05



但IsCancellationRequested并不是唯一担心的方案吗?那么WaitHandle呢? - Tim Lovell-Smith
WaitHandle 如果处置,将被关闭。我不确定是否使用 WaitHandle 是一个常见的用例。我补充说到我的答案。 - Yuval Itzchakov
@Tim我在答案中添加了一个重要的编辑。虽然你想要做的是 可能,我当然不会推荐它。 - Yuval Itzchakov


答案:


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

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

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

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

这意味着,虽然你已经处理了你的CTS,它的对象仍然被令牌引用。因此,它仍然没有资格收集。

现在让我们来看看 CancellationToken.IsCancellationRequested

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

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

作为旁注,如果您(由于某种原因)尝试通过它的处置CancellationTokenSource传递令牌,您将会遇到 ObjectDisposedException

编辑:

我要添加两件事。首先,我要说我不建议使用这种方法。它应该适用于某些代码执行路径,但不适用于所有代码。 CancellationTokenSource 通常只有在你使用时才能处理 WaitHandle 属性。否则,可以将其留在GC进行清洁。但是,因为这是一个风味问题,你可以选择你喜欢的。我肯定会建议您在确定任务已经遵守取消请求后才进行处置。

根据用途 WaitHandle一旦你处理掉它,它就会被处理掉 将不会 可以到达。


11
2018-04-21 20:05



但IsCancellationRequested并不是唯一担心的方案吗?那么WaitHandle呢? - Tim Lovell-Smith
WaitHandle 如果处置,将被关闭。我不确定是否使用 WaitHandle 是一个常见的用例。我补充说到我的答案。 - Yuval Itzchakov
@Tim我在答案中添加了一个重要的编辑。虽然你想要做的是 可能,我当然不会推荐它。 - Yuval Itzchakov