【问题标题】:Task Cancellation with multiple sources多源任务取消
【发布时间】:2011-09-10 06:34:16
【问题描述】:

我目前有一个应用程序,我在其中创建一系列任务,这些任务一个接一个地执行,取消源可以中断任务之间的执行(即在安全终止点)。我目前仅在管理时使用此取消源类是 Disposed,作为一种干净、快速地中止执行的方法。

我现在有一个用例,我想创建一个自动超时来取消任务序列,以防操作员没有及时响应(一些任务等待操作员与物理机制的交互.) 同时,如果管理类是 Disposed,我仍然需要支持取消。我找到了CancellationTokenSource.CreateLinkedTokenSource,这听起来像是我需要的,但我有一些顾虑:

  1. 多个任务系列可以并行执行,因此我需要为超时取消创建一个新的 CancellationTokenSource,并为我开始的每个任务系列创建一个关联的链接源。 CancellationTokenSource 实现 IDisposable,这意味着我需要保留两个取消源并在最后一个任务完成或任何子任务被取消或故障时处置它们。这似乎相当尴尬,即使有匿名方法闭包的有用魔法(仍然有这些取消源被传递。)

  2. 我还需要防止在计时器到期之前释放取消源的情况(所以我不取消已释放的源。)这是一个潜在的竞争条件,所以我需要添加适当的锁定.这似乎也很尴尬,增加了显着的复杂性(未来的维护成本)并使单元测试更具挑战性(竞争条件很难可靠地诱导。)

我是走在正确的道路上还是有更简单的方法可以做到这一点?

【问题讨论】:

    标签: c# .net task task-parallel-library cancellation


    【解决方案1】:

    您问题中的核心问题似乎与在您的 Task 和/或 CancellationTokenSource 对象上调用 Dispose() 有关。在这种情况下,我建议不要在这些上调用Dispose,这将大大简化您的设计。

    作为理由,我会将您推荐给this thread。特别是,Stephen Toub(负责 Task 的 PM)建议您应该:

    积极处理如果根据您的代码结构,这样做既简单又正确。如果您开始不得不为了 Dispose 进行奇怪的旋转(或者在任务的情况下,使用额外的同步来确保它是安全的,因为 Dispose 只能在任务完成后使用),最好依靠完成照顾事情。

    这听起来就像他最后描述的确切情况 - 你正试图做奇怪的旋转以便在这些对象上调用 Dispose()

    【讨论】:

    • 我已经深深地意识到我应该总是在 IDisposable 对象上调用 Dispose,所以我犹豫是否这样做,即使有 Stephen Toub 的祝福。事实上,CancellationTokenSource.Dispose() 的 MSDN 文档明确指出您应该始终调用 Dispose();这可能只是笼统的废话,但这表明 .NET 团队没有合同义务让 Dispose() 为此类保留“可选”。 msdn.microsoft.com/en-us/library/dd321505.aspx
    • @Dan:我知道 - 但是,请记住,如果您不调用 Dispose(),任何正确实现的 IDisposable 对象都会被终结器“清理”。我觉得你应该总是尝试在任何IDisposable 对象上调用 Dispose(),但是,在某些情况下,你会让你的生活变得更糟,而不仅仅是把它留给终结者。 TPL 是事情变得模糊的领域之一 - 通常 (IMO) 最好不要 Dispose() TPL 对象,因为执行它们所需的工作更有可能引入维护问题和错误。
    • 我绝对明白你的观点(从实际的、完成工作的角度来看),这可能就是我最终会做的事情,但是这些“两害相权取其轻”的情况让我感到厌烦。然而,在这一点上,反对意见更多的是哲学上的,而不是技术上的,这是任何工程都无法解决的。
    • @Dan:我知道你的意思 - 我不“故意”处理一些东西让我很烦恼 - 但归根结底,这是邪恶中的小事......跨度>
    猜你喜欢
    • 2013-09-27
    • 2016-01-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多