如何检查所有任务是否已经正确完成?

8

我在代码中有以下几行:

    var taskA = Task.Factory.StartNew(WorkA);
    var taskB = Task.Factory.StartNew(WorkB);
    var allTasks = new[] { taskA, taskB };

    Task.Factory.ContinueWhenAll(allTasks, tasks => FinalWork(), TaskContinuationOptions.OnlyOnRanToCompletion);

但是,当我运行此代码时,我会遇到以下错误:

在多个任务的延续中排除特定的延续类型是无效的。

这是由选项TaskContinuationOptions.OnlyOnRanToCompletion引起的。

我的问题是如何检查所有任务是否已正确完成它们的工作(所有任务状态为RanToCompletion),然后执行FinalWork()?同时,应用程序执行其他任务。


如果一些“任务”失败了,您想要做什么? - svick
如果一些“任务”失败了,就不应该做任何事情。 - Zen
3个回答

13

根据@Peter Ritchie和@Ben McDougall的答案,我找到了解决方案。我通过删除冗余变量tasksTaskContinuationOptions.OnlyOnRanToCompletion来修改我的代码。

var taskA = Task.Factory.StartNew(WorkA);
var taskB = Task.Factory.StartNew(WorkB);
var allTasks = new[] { taskA, taskB };
Task.Factory.ContinueWhenAll(allTasks, FinalWork);

在这里 FinalWork 指:

private static void FinalWork(Task[] tasks)
{
   if (tasks.All(t => t.Status == TaskStatus.RanToCompletion))
   {
        // do "some work"
   }
}

如果所有的任务状态都是RanToCompletion,那么将会完成一些工作。这些工作会在所有任务完成后立即执行,不会阻塞主任务。如果我取消了至少一个任务,则不会执行任何工作。
或者,您可以这样做,
var taskA = Task.Factory.StartNew(WorkA);
var taskB = Task.Factory.StartNew(WorkB);
var allTasks = new[] { taskA, taskB };
var continuedTask = Task.WhenAll(allTasks).ContinueWith((antecedent) => { /*Do Work*/ }, TaskContinuationOptions.OnlyOnRanToCompletion));

替代方案似乎是正确的选择 - 甚至文档也建议使用它。 - wondra

3
您没有提供任何处理已完成任务的代码(您忽略了tasks变量)。如果您只是删除TaskContinuationOptions.OnlyOnRanToCompletion,则会得到相同的结果。也就是说,如果您可以使用TaskContinuationOptions.OnlyOnRanToCompletionContinueWhenAll,则只有在所有任务已完成或失败后才会调用您的继续操作。如果您只需使用已完成的任务,那么与Task.Factory.ContinueWhenAll(allTasks, tasks => FinalWork());相同。
如果您有更具体的要求,请提供详细信息以便其他人能够帮助您。

是的,你说得对。现在我明白变量 tasks 是多余的了。所有关于任务状态的信息都可以通过变量 allTasks 传递给函数。 - Zen

1
回答你提出的实际问题:
“我的问题是如何检查所有任务是否已正确完成(所有任务状态均为RanToCompletion),然后执行FinalWork()?同时,应用程序执行其他任务。”
至少这是我读到的问题,请检查以下代码:
    var taskA = Task.Factory.StartNew(WorkA);
    var taskB = Task.Factory.StartNew(WorkB);
    var allTasks = new[] { taskA, taskB };

    taskA.Wait();
    taskB.Wait();

    if (taskA.Status == TaskStatus.RanToCompletion && taskB.Status == TaskStatus.RanToCompletion)
        Task.Factory.ContinueWhenAll(allTasks, tasks => FinalWork());
    else
        //do something

如果你的意思是这样的话,你实际上已经通过你的问题回答了它。


谢谢您的回答。不幸的是,这个解决方案正在使用Task.Wait方法阻塞主任务。 - Zen
@Zen 我在任务声明和等待之间添加了一些任务,它们可以很好地执行而不会锁定,稍后再看看你的问题。 - Ben McDougall
@Zen:我添加了一个新的类,其中包含一个线程,一切都很顺利。没有任何锁定,一切都运行得很顺畅。就目前而言,我需要更多关于你的问题的信息。基本上,在任务之前添加了一个启动线程的构造函数,并添加了一个类: code var taskC = Task.Factory.StartNew(WorkC); JustAnotherThread jt = new JustAnotherThread(); var taskA = Task.Factory.StartNew(WorkA);`code` - Ben McDougall

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接