Is it safe to call CancellationTokenSource.Cancel multiple times?
Asked Answered
N

2

7

For example, if I want to cancel some operation in a Dispose() call (which can be called multiple times), then do I need to write

public void Dispose()
{
    if (!cancellationTokenSource.IsCancellationRequested)
    {
        cancellationTokenSource.Cancel();
    }
}

or is it enough with the simpler

public void Dispose()
{
    cancellationTokenSource.Cancel();
}

(You are welcome to comment on whether it is wise or not to cancel things in a Dispose method, but that is not the point of this question.)

Nasal answered 15/10, 2018 at 21:22 Comment(0)
N
10

Yes.

But only if the CancellationTokenSource has not been disposed yet.

From the reference source:

ThrowIfDisposed();

// ...

// fast-path test to check if Notify has been called previously
if (IsCancellationRequested)
    return;
Nasal answered 15/10, 2018 at 21:22 Comment(0)
S
0

This seems more a question about the Dispose pattern, then about CancellationToken or anything else. And I am uncertain if you implemented said pattern properly. Here is the official MS Document on the mater: https://learn.microsoft.com/en-us/dotnet/standard/design-guidelines/dispose-pattern

And here my interpretation:

There is two levels of Disposing: Dispose and Finalizsation. As the code for both is very similar, often they are combiend into one function (in C# usually it is Dispose one). The main difference is if you relay it to contained classes. You always relay a Dispose call(the relay is usually what Dispose is about). You never relay a Finalization call (Finalisation is between that instance and the GC only).

There are also two cases: One in wich you handle Unmanaged resources directly. And one in wich you handle just another Disposeable class.

Unamanged resource directly

In this case the first thing you do is implement a Finalizer, so at least the GC can reliably clean this up. Then you implement IDisposeable as an additional feature so programmers can use stuff like the using pattern to have it cleaned up deterministic at runtime.

Handling something that implements IDisposeable

You have a resource that implements IDisposeable (say like a Filestream Reference). You implement IDisposeable in your class for the sole purpose of relaying the Dispose() call to said FileStream. This is the way more common case. It would guess it makes about 95-99% of all Dispose Implementations.

One thing to keep in mind here is that "Dispose" and "Finalize" often implies lower level cleanup. A SQLConenction you call dispose on will be closed first (if nessesary). A Filehandle you Dispose off will also first be closed. Even if calling cancellationTokenSource.Cancel was not repeatable, cancellationTokenSource.Dispose should call Cancel as part of it's operation and should be Repeatable. The class itself does implement IDisposeable. And if any class does, it is usually saver to just call Dispose rather then manually doing the cleanup manually via Cancel: https://learn.microsoft.com/en-us/dotnet/api/system.threading.cancellationtokensource?view=netframework-4.7.2

Spilt answered 15/10, 2018 at 21:53 Comment(1)
Dispose was just an example, the question could be rephrased without it. About calling Dispose instead of Cancel: it won't work in this case, as Dispose will not invoke registered callbacks, is not threadsafe (as opposed to Cancel), and if the CTS is also canceled by others, or is otherwise used, it will lead to ObjectDisposedExceptions.Nasal

© 2022 - 2024 — McMap. All rights reserved.