等待有条件的继续任务的一件事

时间:2015-02-19 17:35:02

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

我想运行这样的东西并等待它,作为一个整体:

            Task task1 = Task.Factory.StartNew(() => MethodThatCouldThrow());

            Task task2 = task1.ContinueWith(t => HandleFailure(t.Exception),
                TaskContinuationOptions.OnlyOnFaulted);

请注意,已经就该主题进行了一些讨论(下面的链接),但他们并没有完全回答这个问题:

  1. 如何等待一件事以确保工作已完成(*工作被定义为主要任务加上可能的延续)
  2. 如何避免正常情况下的异常处理。正常情况是:

    • task1完成(RanToCompletion),task2不运行(已取消)
    • task1 fault(Faulted),但task2成功处理它(RanToCompletion) (其他情况不正常,应抛出,例如task2故障)
  3. 为什么我不能在task2上等待?因为它取消了"取消了"如果task1成功。

    为什么我不能在task1上等待?因为它是" Faulted"如果失败(并且task2可能仍在运行)。

    为什么我不能等待这两项任务?因为task2是"已取消"如果task1成功,则等待抛出。

    一些可能的解决方法(但是它们不符合所需的条件):

    • 无条件继续,检查做什么
    • 条件延续但更复杂的等待,例如,等待task2并在task1成功时忽略取消异常。

    我能找到的相关主题:

    Waiting on a Task with a OnlyOnFaulted Continuation causes an AggregateException

    Using Tasks with conditional continuations

    谢谢!

2 个答案:

答案 0 :(得分:1)

您应该先等到两个任务完成。 然后使用您喜欢的任何谓词检查任务,并根据它来决定。

您可以通过简单地忽略等待抛出的任何异常(我认为它是脏的,因为它是基于异常的控制流)来等待这两个任务,或者:

var combinedTask = Task.WhenAll(t1, t2);
var combinedTaskNoError = waitTask.ContinueWith(_ => { }, TCO.ExecuteSynchronously);

await combinedTaskNoError; //Will not throw.

该中间行应该可以封装在辅助方法中。我称之为WhenCompleted

答案 1 :(得分:1)

使用Task.WhenAll(task1,task2).Wait()的第一点就足够了。

关于你的第二点,你可以忽略任务2被取消,如此

combinedTask.ContinueWith(_=>{
    if (_.IsFaulted){
        if (typeof(_.Exception) == typeof(TaskCancelledException){
            // Do Nothing
        }
    }
})

如果你知道task1失败的异常类型,你可以用同样的方式处理它。根据您将任务链接在一起的方式,它只能生成AggregateExceptions,这意味着您需要对InnnerExceptions执行Exception类型检查,直到您到达不属于AggregateException类型的异常