Task.ContinueWith() 父任务不会等待子任务完成

6

由于我在嵌套任务的上下文中理解了Task,因此我真的不明白为什么第三个打印在第二个之前。

即使我使用了Task.WaitAll(t),它仍然会在第二行之前打印出第三行

代码:

public static void Main()
        {

            Task t = new Task(
                () =>
                {
                    Thread.Sleep(2000);
                    Console.WriteLine("1st print...");
                });
           t.ContinueWith(
                x =>
                {
                    Thread.Sleep(2000);
                    Console.WriteLine("2nd print...");
                },
                TaskContinuationOptions.OnlyOnRanToCompletion);

            t.Start();
            Task.WaitAll(t);

            Console.WriteLine("3rd print...");
            Console.Read();

}

输出:

输入图像描述


1
@nunu 除了将您想要等待的所有任务传递给 WaitAll,没有其他解决方案,这就是为什么需要复制。无法添加任何内容到该问题中已经写好的内容。也没有“WaitAllAndChildren”方法。 - Andrey
2
我认为你只是误解了你的代码:Task.Wait正在等待主任务结束。当它结束时,它会在主线程上继续执行(因此写入“第三行”),同时主任务也会同时运行继续任务(因此写入“第二行”)。除非你以某种方式等待这个第二个(子)任务,否则这两个任务的顺序不能保证。这个“某种方式”是指Task.Wait应该等待这个子任务。没有其他办法。 - Jcl
谢谢@Jcl。实际上,我的理解是-如果我在子任务中使用'TaskContinuationOptions.AttachedToParent'选项,我认为子任务会附加到父任务。现在,如果我等待父任务,子任务将自动等待。 - nunu
1
附加任务,简单来说,只是指示状态和异常应该在父任务和子任务之间“共享”...它不会“扩展您的原始任务而不创建另一个”(此外,在您的示例代码中未使用AttachedToParent)。 - Jcl
1
你应该阅读并尝试理解这个链接:http://msdn.microsoft.com/zh-cn/library/ee372288(v=vs.110).aspx(第一次阅读可能不容易,但要实践)。 - Jcl
显示剩余7条评论
3个回答

8

您需要等待继续执行:

Task t2 = t.ContinueWith( /* .. */ );
Task.WaitAll(new [] { t, t2 } );

谢谢@Jcl!但是,我不想创建多个任务。我希望用一个单一的任务来处理这个问题。当然,我们可以在一个父任务中创建嵌套任务作为子任务,但不能完全是不同的任务。 - nunu
5
您正在使用 ContinueWith,因此已经创建了第二个任务......只是您没有存储ContinueWith函数的结果,但这并不意味着该任务未被创建。 - Jcl

4
你只等待了t,而没有等待它的延续。这就是为什么该延续将在未来某个时刻运行的原因。如果没有Console.Read,则它可能永远不会在进程退出之前运行。 Task.WaitAll(t) 等同于 t.Wait() (你应该使用后者,因为它更符合惯用语法)。
让它等待所有延续(可能是递归的)会导致不直观的行为并产生非本地影响。程序的远程部分可能会影响你的代码。

谢谢@usr!现在的问题是,我该如何等待嵌套任务完成?? - nunu
将该任务存储在某个地方并等待它。 - usr

0

你做了一个假设,认为它应该等待子任务完成,但没有依据来做这样的假设。从MSDN上可以看到:

Task.WaitAll: 等待所有提供的Task对象执行完成。

它就是按照字面意思执行的。`ContinueWith`不会改变原始任务的长度,不会变得更长。它只是紧接着执行。


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