The class CancellationTokenSource
is disposable. A quick look in Reflector proves usage of KernelEvent
, a (very likely) unmanaged resource.
Since CancellationTokenSource
has no finalizer, if we do not dispose it, the GC won't do it.
On the other hand, if you look at the samples listed on the MSDN article Cancellation in Managed Threads, only one code snippet disposes of the token.
What is the proper way to dispose of it in code?
- You cannot wrap code starting your parallel task with
using
if you do not wait for it. And it makes sense to have cancellation only if you do not wait. - Of course you can add
ContinueWith
on task with aDispose
call, but is that the way to go? - What about cancelable PLINQ queries, which do not synchronize back, but just do something at the end? Let's say
.ForAll(x => Console.Write(x))
? - Is it reusable? Can the same token be used for several calls and then dispose it together with the host component, let's say UI control?
Because it does not have something like a Reset
method to clean-up IsCancelRequested
and Token
field I would suppose it's not reusable, thus every time you start a task (or a PLINQ query) you should create a new one. Is it true? If yes, my question is what is the correct and recommended strategy to deal with Dispose
on those many CancellationTokenSource
instances?
Create a new Windows Forms application from the project template. Drop a button on the form and double click it. Make it look like this:
Press Ctrl+F5 to start it. Start + Run, TaskMgr.exe, Processes tab. View + Select Columns and tick "Handles". Observe the value of this column for the WindowsFormsApplication1.exe process while you click the button repeatedly.
The Thread class doesn't have a Dispose() method.
Let's work from the assumption that it had one. When would you call it?
Read more about the wisdom of trying to dispose hard-to-dispose objects in this blog post by Stephen Toub.
It has been a long time since I asked this and got many helpful answers but I came across an interesting issue related to this and thought I would post it here as another answer of sorts:
You should call
CancellationTokenSource.Dispose()
only when you are sure that nobody is going to try to get the CTS'sToken
property. Otherwise you should not call it, because it is a race. For instance, see here:https://github.com/aspnet/AspNetKatana/issues/108
In the fix for this issue, code which previously did
cts.Cancel(); cts.Dispose();
was edited to just docts.Cancel();
because anyone so unlucky as to try to get the cancellation token in order to observe its cancellation state after Dispose has been called will unfortunately also need to handleObjectDisposedException
- in addition to theOperationCanceledException
that they were planning for.Another key observation related to this fix is made by Tratcher: "Disposal is only required for tokens that won't be cancelled, as cancellation does all of the same cleanup." i.e. just doing
Cancel()
instead of disposing is really good enough!You should always dispose
CancellationTokenSource
.How to dispose it depends exactly on the scenario. You propose several different scenarios.
using
only works when you're usingCancellationTokenSource
on some parallel work that you're waiting. If that's your senario, then great, it's the easiest method.When using tasks, use a
ContinueWith
task as you indicated to dispose ofCancellationTokenSource
.For plinq you can use
using
since you're running it in parallel but waiting on all of the parallel running workers to finish.For UI, you can create a new
CancellationTokenSource
for each cancellable operation that is not tied to a single cancel trigger. Maintain aList<IDisposable>
and add each source to the list, disposing all of them when your component is disposed.For threads, create a new thread that joins all the worker threads and closes the single source when all of the worker threads finished. See CancellationTokenSource, When to dispose?
There's always a way.
IDisposable
instances should always be disposed. Samples often don't because they're either quick samples to show core usage or because adding in all aspects of the class being demonstrated would be overly complex for a sample. The sample is just that a sample, not necessarily (or even usually) production quality code. Not all samples are acceptable to be copied into production code as is.This answer is still coming up in Google searches, and I believe the voted up answer is does not give the full story. After looking over the source code for
CancellationTokenSource
(CTS) andCancellationToken
(CT) I believe that for most use cases the following code sequence is fine:The
m_kernelHandle
internal field mentioned above is the synchronization object backing theWaitHandle
property in both the CTS and CT classes. It is only instantiated if you access that property. So, unless you are usingWaitHandle
for some old-school thread synchronization in yourTask
calling dispose will have no effect.Of course, if you are using it you should do what is suggested by the other answers above and delay calling
Dispose
until anyWaitHandle
operations using the handle are complete, because, as is described in the Windows API documentation for WaitHandle, the results are undefined.I took a look in ILSpy for the
CancellationTokenSource
but I can only find m_KernelEvent which is actually aManualResetEvent
, which is a wrapper class for a WaitHandle object. This should be handled properly by the GC.Speaking about whether it's really necessary to call Dispose on
CancellationTokenSource
... I had a memory leak in my project and it turned out thatCancellationTokenSource
was the problem.My project has a service, that is constantly reading database and fires off different tasks, and I was passing linked cancellation tokens to my workers, so even after they had finished processing data, cancellation tokens weren't disposed, which caused a memory leak.
MSDN Cancellation in Managed Threads states it clearly:
I used
ContinueWith
in my implementation.