4

C# 仕様 4.0 セクション 7.15.5.1:

キャプチャされていない変数とは異なり、キャプチャされたローカル変数は複数の実行スレッドに同時に公開できることに注意してください。

「複数の実行スレッド」とは正確にはどういう意味ですか? これは、複数のスレッド、複数の実行パス、または他の何かを意味しますか?

例えば

        private static void Main(string[] args)
        {
            Action[] result = new Action[3];
            int x;
            for (int i = 0; i < 3; i++)
            {
                //int x = i * 2 + 1;//this behaves more intuitively.  Outputs 1,3,5
                x = i*2 + 1;
                result[i] = () => { Console.WriteLine(x); };
            }
            foreach (var a in result)
            {
                a(); //outputs 5 each time
            }

            //OR...

            int y = 1;            
            Action one = new Action(() =>
            {
                Console.WriteLine(y);//Outputs 1
                y = 2;                
            });

            Action two = new Action(() =>
            {
                Console.WriteLine(y);//Outputs 2.  Working with same Y
            });

            var t1 = Task.Factory.StartNew(one);
            t1.Wait();
            Task.Factory.StartNew(two);
            Console.Read();
        }

Hereは、宣言さxれている場所に基づいて異なる動作を示します。x同じ変数の場合、y複数のスレッドによってキャプチャされて使用されますが、IMO のこの動作は直感的です。

彼らは何を指していますか?

4

3 に答える 3

1

以下のリンクを参照してください。

外部変数nへの参照は、デリゲートが作成されたときにキャプチャされたと言われます。ローカル変数とは異なり、キャプチャされた変数の有効期間は、匿名メソッドを参照するデリゲートがガベージコレクションの対象となるまで延長されます。

つまり、変数のメモリ位置は、メソッドが作成されたときにキャプチャされ、そのメソッドと共有されます。スレッドがその変数から匿名メソッドを除いたものにアクセスできる場合と同じです。意図しない結果を引き起こさないようにローカルの一時変数に移動することを提案する場合に発生するコンパイラ警告があります。

MSDN匿名メソッド

于 2013-03-06T15:06:54.150 に答える
1

「実行の複数のスレッド」とは、単に複数のスレッドを意味します。つまり、同時に実行されている複数のスレッド。特定の変数が複数のスレッドに公開されている場合、それらのスレッドのいずれかがその変数の値を読み書きできます。

これは潜在的に危険であり、可能な限り避ける必要があります。シナリオで許可されている場合、これを回避する1つの可能性は、タスクのメソッドに変数のローカルコピーを作成することです。

于 2013-03-06T14:35:36.020 に答える
1

コードの 2 番目の部分を少し変更すると、次のようになります。

        int y = 1;
        Action one = new Action(() =>
        {
            Console.WriteLine(y);//Outputs 1
            y = 2;
        });

        Action two = new Action(() =>
        {
            Console.WriteLine(y);//Outputs 2.  Working with same Y
            y = 1;
        });

        var t1 = Task.Factory.StartNew(one);
        t1 = Task.Factory.StartNew(two);
        t1.Wait();
        t1 = Task.Factory.StartNew(one);
        t1.Wait();
        t1 = Task.Factory.StartNew(two);

        Console.Read();

数回実行するか、ループに入れてください。異なる、一見ランダムな結果を出力します (例:1 1 1 2または ) 1 2 1 2

複数のスレッドが同じ変数にアクセスし、同時に取得および設定しているため、予期しない結果が生じる可能性があります。

于 2013-03-06T14:43:34.537 に答える