7

在下面的代码片段中,一个任务使用 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.");
}

输出:

Main start.
Calling Result.
In parent start
In parent end
In child 1:101
In child 2:102
100
Main end.
4

2 回答 2

5

问题是您创建c1c2作为单独的任务,但随后i立即从t1之前返回c1c2增加了i.

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

正如您所指出的,这种安排在父/子关系中没有多大意义。但在很多情况下它确实有意义。

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

当然,您可以通过添加来修复它

Task.WaitAll(c1, c2);

就在return i;. 我知道这不是你要问的,但我只是想指出这一点。

于 2013-05-27T10:25:22.910 回答
-1

如前所述, i 的值在递增之前返回。以这种方式更改代码会返回预期值(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(() => {
        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.");
 }

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

于 2013-05-27T10:31:54.590 回答