【问题标题】:Who canceled my Task?谁取消了我的任务?
【发布时间】:2013-01-12 09:15:38
【问题描述】:

我的 C# 任务被取消了,但不是我。我没有得到堆栈跟踪,也无法确定问题出在哪里。

我的任务调用如下所示:

var t = Task<Boolean>.Factory.StartNew(() =>
    {
        Boolean bOk = DoSomthingImportant();
        return bOk;
    }, TaskCreationOptions.AttachedToParent)
    .ContinueWith<Boolean>((theTask) =>
    {
        var reason = theTask.IsCanceled ? "it was canceled" : "it faulted";
        Debug.WriteLine("Error: Task ended because " + reason + ".");
        ... log the exception to one of my objects...
        return false;
    }, TaskContinuationOptions.NotOnRanToCompletion);

如果任务出错或被取消,我希望继续任务运行,但如果运行正常则不运行。 延续永远不会执行。

稍后我的程序捕获了一个 AggregateException,它包装了一个 TaskCanceledException。

我与任务的其他主要交互是调用 WaitAny(taskArray, timeout) 直到我没有更多任务要启动,然后调用 WaitAll 直到最后一个任务完成为止。

超时的 WaitAny 会导致取消吗?为什么我的延续没有被调用?

这只是我第二次刷任务库,所以我一无所知。

更新:

我发现了这个 SO 问题:如何将任务的已取消状态传播到继续任务。 上面代码中的一个错误(但不是取消的原因)是我假设继续任务状态与原始任务的状态相同。事实上,正如另一篇文章所述,您必须做一些工作才能从另一个那里得到一个。

更新 2:

Brian:感谢您提供文档参考。我已经在高低搜索了任务被取消的其他原因,但错过了这些词:

"如果您正在等待一个转换为已取消状态的任务, 制造并抛出一个任务(包装在 AggregateException 中)。 请注意,此异常表示成功取消而不是 错误的情况。因此,Task 的 Exception 属性返回 空。”

【问题讨论】:

  • 不知道您的问题是什么,但您可能不知道在访问Task.Factory(在Task 上定义)和调用ContinueWith(它将根据您返回的内容进行推断)。当然它对错误没有帮助,只是使语法更短。
  • 谢谢你的小费,丹。我喜欢简洁的代码。

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


【解决方案1】:

您正在等待继续,并且由于原始任务运行完成,因此取消了继续任务。 the documentation 中涵盖了此行为。

【讨论】:

  • 你是认真的吗?那太疯狂了。逻辑一致,但很疯狂。我会调查的。
  • 在您的示例中,t 指向延续。对原始任务的唯一引用是theTask。您希望在这一点上延续什么状态?
  • @PaulChernoch 你认为这是疯狂的 API 设计吗?它实际上是非常合理的设计,因为它允许您以不同的方式对待任务及其延续。它们是单独的任务。您在它们上链式调用方法的事实并不是 TPL 可以(神奇地)知道并做出反应的事实。
  • 如果你是对的,并且我捕获了要等待的正确任务,如果 Continuation 任务因为不需要而被取消,我是否必须做任何事情来防止它引发异常?我如何以及在哪里检测到这种情况?
  • 抱歉,我不确定我是否关注。底线是,如果您 Wait 处理已取消的任务,则会触发异常。虽然这可能会令人困惑,但允许等待已取消的任务会更加令人困惑,因为您无法判断它是运行完成还是被取消。
猜你喜欢
  • 1970-01-01
  • 2013-09-15
  • 1970-01-01
  • 1970-01-01
  • 2018-12-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多