父任务不等待子任务完成

7
所以下面是我的代码。
Task<int[]> parent = Task.Run(() =>
{
    var result = new int[3];

    TaskFactory tf = new TaskFactory(TaskCreationOptions.AttachedToParent, TaskContinuationOptions.ExecuteSynchronously);

    for (int i = 0; i < result.Length; i++)
    {
        int j = i;
        tf.StartNew(() => result[j] = GetRandomNumber(j));
    }

    return result;
});

var finalTask = parent.ContinueWith(parentTask =>
{
    foreach (var i in parentTask.Result)
    {
        Console.WriteLine(i);   
    }
});

finalTask.Wait();

基本上,我创建了3个子任务,它们是名为父任务的Task的子任务(我猜测)。我期望父任务等待所有三个子任务完成。之后,由于`finalTask.Wait();`这个语句,`finalTask`将等待执行。但事情并没有按照预期发生。我的意思是,在任何一个`GetRandomNumber`调用完成之前,应用程序就退出了。此处的代码有一部分是从书中复制的,该书指出这些父任务应该等待子任务完成,但显然并没有发生。我在这里漏掉了什么吗?
以下是"GetRandomNumber"函数的内容:
public static int GetRandomNumber(int ii)
{
    Random rand = new Random();

    for (int i = 0; i < 1000000000; i++) { } // imitate some jobs

    return rand.Next(1000);
}

这段代码实现了同样的功能。

Task<int[]> parent = Task.Run(() =>
{
    var result = new int[3];

    for (int i = 0; i < result.Length; i++)
    {
        int j = i;
        new Task(() => result[j] = GetRandomNumber(j), TaskCreationOptions.AttachedToParent).Start();
    }

    return result;
});

这只是一个例子。 - Dimitri
逐步执行代码并查看其操作。 - SQLMason
GetRandomNumber被调用了3次,但是方法的结尾从未被执行。 - Dimitri
3个回答

14
这种行为是由于您使用了 Task.Run 方法,该方法禁止子任务附加到父任务:

Run 方法是 StartNew 方法的简单替代方案。它创建一个任务,其 CreationOptions 属性值为 TaskCreationOptions.DenyChildAttach

要解决问题,只需将第一行改为

Task<int[]> parent = Task.Run(() =>

Task<int[]> parent = Task.Factory.StartNew(() =>

8
Task.Run的文档中,你会发现它指定了:

它的CreationOptions属性值为TaskCreationOptions.DenyChildAttach。

所以,即使你指定了TaskCreationOptions.AttachedToParent,它也会被忽略。


我正要发布这个,它会导致相同的结果:http://social.msdn.microsoft.com/Forums/vstudio/en-US/6e142b15-0e41-4cbc-bccc-bb7bdebe0795/how-does-taskcreationoptionsattachedtoparent-work-on-task-hierarchy?forum=parallelextensions - SQLMason

2
请使用以下代码:
static void RunParentTask()
    {
        Task<int[]> parent = Task.Factory.StartNew<int[]>(() =>
        {
            var results = new int[3];

            TaskFactory<int> factory = new TaskFactory<int>(TaskCreationOptions.AttachedToParent,
                                                            TaskContinuationOptions.ExecuteSynchronously);
            factory.StartNew(() => results[0] = 1);
            factory.StartNew(() => results[1] = 2);
            factory.StartNew(() => results[2] = 3);

            return results;
        });

        parent.Wait();

        foreach (var item in parent.Result)
        {
            Console.WriteLine(item);
        }
    }

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