Is code that disposes CancellationTokenSource while tasks are canceling correct?

前端 未结 1 337
南笙
南笙 2021-01-01 20:47

I see this code in front of me and I am suspicious:

CancellationTokenSource _cts;

public void Dispose();
{
    _cts.Cancel();
    _cts.Dispose();
    _task.         


        
相关标签:
1条回答
  • 2021-01-01 21:15

    Is it safe to call _cts.Dispose() straight after cancel?

    In order to know that, we need to understand what happens when we cancel a CancellationTokenSource.

    When you cancel a CancellationTokenSource, it goes on to invoke any callbacks registered via the CancellationToken, which holds a reference to it's parent source via the CancellationToken.Register() method.

    When you dispose a CTS, any linking callback that was registered is attempted to be unregistered from the token. If it's currently executing, it will wait until it's delegate is complete.

    Which means, that although you've disposed your CTS, it's object is still referenced by the token. Hence, it still isn't eligible for collection.

    Now let's look at CancellationToken.IsCancellationRequested:

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

    This means that while disposed, checking the cancellation will yield true. This means, that it is safe for you to wait on the tasks completion after calling dispose.

    As a side note, if you (for some reason) try to pass a token via it's disposed CancellationTokenSource, you will hit an ObjectDisposedException.

    Edit:

    Two things I want to add. First, let me say that I don't recommend using this approach. It should work for some code execution paths, but not for all. CancellationTokenSource should normally be disposed only if you use it's WaitHandle property. Otherwise, it is fine to leave it up to the GC to do the cleaning. But, as this is a matter of flavor, you may choose whichever you like. I would certainly advise to dispose only after you're certain the task has observed the cancellation request.

    As per usage of WaitHandle, it will be disposed and nulled out once you dispose, so it will not be reachable.

    0 讨论(0)
提交回复
热议问题