C# 从父子任务返回值

C# 从父子任务返回值,c#,task-parallel-library,C#,Task Parallel Library,在下面的代码段中,任务使用TaskCreationOptions.AttachedToParent创建两个子任务,这意味着父任务将等待子任务完成 问题是-为什么父任务不返回正确的值[102]?它是否首先确定其返回值,然后等待子任务完成。如果是这样,那么创建父子关系的意义何在 void Main() { Console.WriteLine ("Main start."); int i = 100; Task<int> t1 = new Task<int>(()=>

在下面的代码段中,任务使用TaskCreationOptions.AttachedToParent创建两个子任务,这意味着父任务将等待子任务完成

问题是-为什么父任务不返回正确的值[102]?它是否首先确定其返回值,然后等待子任务完成。如果是这样,那么创建父子关系的意义何在

void Main()
{
Console.WriteLine ("Main start.");
int i = 100;

Task<int> t1 = new Task<int>(()=> 
{
    Console.WriteLine ("In parent start");
    Task c1 = Task.Factory.StartNew(() => {
        Thread.Sleep(1000);
        Interlocked.Increment(ref i);
        Console.WriteLine ("In child 1:" + i);
    }, TaskCreationOptions.AttachedToParent);

    Task c2 = Task.Factory.StartNew(() => {
        Thread.Sleep(2000);
        Interlocked.Increment(ref i);           
        Console.WriteLine ("In child 2:" + i);
    }, TaskCreationOptions.AttachedToParent );

    Console.WriteLine ("In parent end");
    return i;
}); 

t1.Start();
Console.WriteLine ("Calling Result.");
Console.WriteLine (t1.Result);
Console.WriteLine ("Main end.");
}

问题是,您将
c1
c2
创建为单独的任务,但在
c1
c2
增加
i
之前,立即从
t1
返回
i

因此,
t1
的返回值在该点被捕获,并且仍然是
100

正如您所指出的,这种安排在父母/子女关系中没有多大意义;但在很多情况下,这是有意义的

一个常见的用法是,父任务在其子任务完成之前不会完成,但是如果您要求父任务在返回值之前等待其子任务,您将无法这样做

当然,您可以通过添加

Task.WaitAll(c1, c2);

就在
返回i之前。我知道这不是你要问的,但我只是想指出这一点。

如前所述,I的值在递增之前返回。以这种方式更改代码将返回预期值(102):

void Main()
{
Console.WriteLine(“主启动”);
int i=100;
任务t1=新任务(()=>
{
Console.WriteLine(“在父级启动中”);
Task c1=Task.Factory.StartNew(()=>{
联锁增量(参考i);
Console.WriteLine(“在子项1中:+i”);
},TaskCreationOptions.AttachedToParent);
睡眠(1000);
Task c2=Task.Factory.StartNew(()=>{
联锁增量(参考i);
Console.WriteLine(“在孩子2中:+i”);
},TaskCreationOptions.AttachedToParent);
睡眠(1000);
Console.WriteLine(“在父端”);
返回i;
}); 
t1.Start();
Console.WriteLine(“调用结果”);
Console.WriteLine(t1.Result);
Console.WriteLine(“主端”);
}

我所做的只是将Thread.Sleep(1000)从子任务取出到父任务。现在在变量递增后返回结果。

这是一个糟糕的答案。睡眠被添加到子任务中以模拟长时间工作。将它们转移到主要任务是穷人的同步机制。当然可以,除非child taks需要超过1000毫秒才能完成。考虑到我们有很多很多方法来同步.NET中的数据,使用睡眠来实现这一点是最糟糕的解决方案,您永远不应该这样做use@Pako我同意你的观点,但我只是想指出为什么int变量在两个任务结束时没有被更新。是的,等待和返回值是不同的事情,但是为什么不在决定返回值之前等待呢。你认为这可能是第三方物流中的一个bug吗?@wpfguy不,这绝对不是bug。如果某个任务的结果在启动第一个任务的任务访问第一个任务的返回值之前退出,则缓存该任务的结果,这是一个自然结果。
Task.WaitAll(c1, c2);
void Main()
{
    Console.WriteLine ("Main start.");
    int i = 100;

    Task<int> t1 = new Task<int>(()=> 
    {


    Console.WriteLine ("In parent start");
    Task c1 = Task.Factory.StartNew(() => {
        Interlocked.Increment(ref i);
        Console.WriteLine ("In child 1:" + i);
    }, TaskCreationOptions.AttachedToParent);

    Thread.Sleep(1000);

    Task c2 = Task.Factory.StartNew(() => {
        Interlocked.Increment(ref i);           
        Console.WriteLine ("In child 2:" + i);
    }, TaskCreationOptions.AttachedToParent );

    Thread.Sleep(1000);

    Console.WriteLine ("In parent end");
    return i;
}); 

t1.Start();
Console.WriteLine ("Calling Result.");
Console.WriteLine (t1.Result);
Console.WriteLine ("Main end.");
 }