父任务忽略子任务

时间:2015-03-26 10:57:44

标签: c# multithreading task-parallel-library task

在下面的代码中,我预计结果为3

        Task<int> parent = Task.Factory.StartNew(() =>
        {
            var sum = 0;
            TaskFactory tf = new TaskFactory(TaskCreationOptions.AttachedToParent,
            TaskContinuationOptions.ExecuteSynchronously);
            tf.StartNew(() => sum++);
            tf.StartNew(() => sum++);
            tf.StartNew(() => sum++);
            return sum;
        });
        var finalTask = parent.ContinueWith(parentTask => Console.WriteLine(parentTask.Result));
        finalTask.Wait();

然而结果是0,我不明白。奇怪的是,当我改变它使用和数组它似乎做了正确的事情。

Task<Int32[]> parent = Task.Factory.StartNew(() =>
        {
            var results = new Int32[3];
            TaskFactory tf = new TaskFactory(TaskCreationOptions.AttachedToParent,
            TaskContinuationOptions.ExecuteSynchronously);
            tf.StartNew(() => results[0] = 0);
            tf.StartNew(() => results[1] = 1);
            tf.StartNew(() => results[2] = 2);
            return results;
        });
        var finalTask = parent.ContinueWith(
        parentTask =>
        {
            foreach (int i in parentTask.Result)
                Console.WriteLine(i);
        });
        finalTask.Wait();

此处结果如预期: 0 1 2

我想我错过了一些非常明显的东西,我需要在第一段代码中修复它才能让它返回3

更新 我已经看过这个Solution这就是为什么我没有使用Task.Run但它并没有真正有所作为

1 个答案:

答案 0 :(得分:3)

由值类型与参考类型语义的差异引起的案例之间的差异。 int是值类型,因此在返回时复制,并且不会看到对sum变量的任何后续更改。数组是引用类型,因此只返回复制引用,因此子任务所做的数组中的任何更改都是可见的,因为它是相同的数组。要使您的第一个案例有效,您需要使用某种引用类型替换int

public class Reference<T> {
    public T Value;
    public Reference(T value) {
        Value=value;
    }
}
public static void Test() {
    Task<Reference<int>> parent=Task.Factory.StartNew(() => {
        var sum=new Reference<int>(0);
        TaskFactory tf=new TaskFactory(TaskCreationOptions.AttachedToParent,
        TaskContinuationOptions.ExecuteSynchronously);
        tf.StartNew(() => sum.Value++);
        tf.StartNew(() => sum.Value++);
        tf.StartNew(() => sum.Value++);
        return sum;
    });
    var finalTask=parent.ContinueWith(parentTask => Console.WriteLine(parentTask.Result.Value));
    finalTask.Wait();
}