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

Tim*_*ith 13 .net c# cancellationtokensource

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

CancellationTokenSource _cts;

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

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

Yuv*_*kov 14

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

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

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

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

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

现在让我们来看看CancellationToken.IsCancellationRequested:

public bool IsCancellationRequested 
{
    get
    {
        return m_source != null && m_source.IsCancellationRequested;
    }
}
Run Code Online (Sandbox Code Playgroud)

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

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

编辑:

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

根据使用情况WaitHandle,一旦处理完毕,它将被处理掉,因此无法使用.

  • 但是IsCancellationRequested不是唯一担心这种情况的方案吗?那WaitHandle呢? (2认同)