When to dispose CancellationTokenSource?

2019-01-07 05:10发布

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?

  1. 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.
  2. Of course you can add ContinueWith on task with a Dispose call, but is that the way to go?
  3. 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))?
  4. 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?

7条回答
家丑人穷心不美
2楼-- · 2019-01-07 05:54

I didn't think any of the current answers were satisfactory. After researching I found this reply from Stephen Toub (reference):

It depends. In .NET 4, CTS.Dispose served two primary purposes. If the CancellationToken's WaitHandle had been accessed (thus lazily allocating it), Dispose will dispose of that handle. Additionally, if the CTS was created via the CreateLinkedTokenSource method, Dispose will unlink the CTS from the tokens it was linked to. In .NET 4.5, Dispose has an additional purpose, which is if the CTS uses a Timer under the covers (e.g. CancelAfter was called), the Timer will be Disposed.

It's very rare for CancellationToken.WaitHandle to be used, so cleaning up after it typically isn't a great reason to use Dispose. If, however, you're creating your CTS with CreateLinkedTokenSource, or if you're using the CTS' timer functionality, it can be more impactful to use Dispose.

The bold part I think is the important part. He uses "more impactful" which leaves it a bit vague. I'm interpreting it as meaning calling Dispose in those situations should be done, otherwise using Dispose is not needed.

查看更多
登录 后发表回答