何时处置CancellationTokenSource?

CancellationTokenSource类是一次性的,快速查看reflection器certificate非常可能KernelEvent托pipe资源KernelEvent 。 它没有终结者,所以如果我们不处理,GC就不会这样做。

另一方面,如果您查看MSDN取消文章中的示例,则除了一个之外,所有代码片段都不会这样做。

在代码中find正确的位置和时间似乎很难。

  1. 如果你不等待,你不能用代码开始你的并行任务。 只有在不等待的情况下,取消才有意义。
  2. 当然,你可以用Dispose调用在任务上添加ContinueWith ,但是这是怎么回事?
  3. 关于可取消的PLINQ查询,哪些不同步,但只是在最后做些什么? 比方说.ForAll(x => Console.Write(x))
  4. 它可重用吗? 我们可以重复使用相同的标记进行多个调用,然后将其与主机组件一起处理,让我们说UI控制?

因为它没有类似Reset方法来清理IsCancelRequestedToken字段,所以我认为它是不可重用的,因此每次启动任务(或PLINQ查询)时都应该创build一个新的。 这是真的吗? 如果是的话,我的问题是什么是正确的和build议的策略来处理这些许多CancellationTokenSource实例处理?

说到真的有必要调用DisposeTokenSource Dispose …我的项目中有一个内存泄漏,事实certificateCancellationToken(Source)是问题…

我的项目有一个服务,就是不断的读取数据库,closures不同的任务,我把链接的取消令牌传递给我的工作人员,所以即使在处理完数据之后,也没有处理取消令牌,导致我的内存泄漏案件。

和MSDN http://msdn.microsoft.com/en-us/library/dd997364.aspx实际上清楚地说明了这一点:请注意,当您完成后,您必须在链接的令牌源上调用Dispose。; 有关更完整的示例,请参阅如何:侦听多个取消请求。

我用ContinueWith来做到这一点

我在ILSpy中查看了CancellationTokenSource但是我只能findm_KernelEvent,它实际上是一个ManualResetEvent ,它是一个WaitHandle对象的包装类。 这应该由GC正确处理。

我不认为目前的答案是令人满意的。 经过研究,我发现Stephen Toub的这个回复( 参考 ):

这取决于。 在.NET 4中,CTS.Dispose有两个主要目的。 如果CancellationToken的WaitHandle已被访问(因此懒惰地分配它),Dispose将处理该句柄。 另外,如果CTS是通过CreateLinkedTokenSource方法创build的,则Dispose将取消它与链接到的令牌之间的链接。 在.NET 4.5中,Dispose还有一个额外的目的,就是如果CTS使用了一个Timer(例如CancelAfter被调用),Timer就会被抛弃。

使用CancellationToken.WaitHandle的情况非常罕见,因此在清理之后通常不会使用Dispose。 但是,如果您使用CreateLinkedTokenSource创buildCTS,或者如果您使用CTS的计时器function,那么使用Dispose可能会更有效。

我认为大胆的部分是重要的一部分。 他使用“更有影响力”,这使得它有点模糊。 我把它解释为意义调用Dispose在这些情况下应该完成,否则使用Dispose是不需要的。

您应该始终处理CancellationTokenSource

如何处置它完全取决于场景。 你提出了几种不同的情况。

  1. 只有在您正在等待的某些平行工作中使用CancellationTokenSource时才能使用。 如果这是你的senario,那么很好,这是最简单的方法。

  2. 使用任务时,请按照指示使用ContinueWith任务来处置CancellationTOkenSource

  3. 对于plinq,您可以使用using因为您正在并行运行它,但等待所有并行运行的工作人员完成。

  4. 对于用户界面,您可以为每个与单个取消触发器无关的可取消操作创build一个新的CancellationTokenSource 。 维护一个List<IDisposable>并将每个源添加到列表中,当你的组件被处置时将它们全部处理掉。

  5. 对于线程,创build一个新的线程来join所有工作线程,并在所有工作线程完成时closures单个源。 请参阅CancellationTokenSource,何时处理?

总有办法。 IDisposable实例。 样本往往不是因为它们要么是快速样本来显示核心使用,要么是因为在样本中join被certificate类的所有方面都会过于复杂。 样品只是一个样品,不一定(甚至通常)生产质量代码。 并不是所有的样本都可以被接受的复制到生产代码中。

这个答案仍然在谷歌search,我相信投票答复是不能给出完整的故事。 查看CancellationTokenSource (CTS)和CancellationToken (CT)的源代码后 ,我认为对于大多数使用情况下面的代码序列是好的:

 if (cancelTokenSource != null) { cancelTokenSource.Cancel(); cancelTokenSource.Dispose(); cancelTokenSource = null; } 

上面提到的m_kernelHandle内部字段是支持CTS和CT类中的WaitHandle属性的同步对象。 只有在访问该属性时才会实例化。 所以,除非你在Task调用中使用WaitHandle进行一些老派的线程同步,处置将不起作用。

当然,如果你正在使用它,你应该做上面的其他答案所build议的,并延迟调用Dispose直到使用句柄的任何WaitHandle操作完成为止,因为如WaitHandle的Windows API文档中所述,结果是未定义的。

从项目模板创build一个新的Windows窗体应用程序。 放下窗体上的一个button,然后双击它。 使它看起来像这样:

  private void button1_Click(object sender, EventArgs e) { var t = new System.Threading.Thread(() => { }); t.Start(); } 

按下Ctrl + F5启动它。 开始+运行,TaskMgr.exe,进程选项卡。 查看+select列并勾选“句柄”。 在重复单击button时,请注意WindowsFormsApplication1.exe进程的此列的值。

Thread类没有Dispose()方法。

我们假设它有一个。 你什么时候打电话?


Stephen Toub在本篇博文中详细介绍了试图处理难以处理的对象的智慧。