7

以下のスニペットでは、タスクは TaskCreationOptions.AttachedToParent を使用して 2 つの子タスクを作成します。これは、親タスクが子タスクが完了するまで待機することを意味します。

問題は、親タスクが正しい値 [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

問題は、c1とを別々のタスクとして作成した後、すぐに前からc2戻り、が増加したことです。it1c1c2i

したがって、 からの戻り値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 に答える