5

重複の可能性:
ループ内の C# キャプチャ変数

私はスレッド化のいくつかの単純なアプリケーションに取り組んでいますが、これを機能させることができないようです:

class ThreadTest
{
    static Queue<Thread> threadQueue = new Queue<Thread>();

    static void Main()
    {
        //Create and enqueue threads
        for (int x = 0; x < 2; x++)
        {
            threadQueue.Enqueue(new Thread(() => WriteNumber(x)));
        }

        while(threadQueue.Count != 0)
        {
            Thread temp = threadQueue.Dequeue();
            temp.Start();
        }

        Console.Read();
    }

    static void WriteNumber(int number)
    {
        for (int i = 0; i < 1000; i++)
        {
            Console.Write(number);
        }
    }
}

目標は基本的に、スレッドをキューに 1 つずつ追加してから、キューを 1 つずつ調べて、スレッドをポップオフして実行することです。for ループに "x<2" があるため、2 つのスレッドのみを作成する必要があります。1 つは WriteNumber(0) を実行するスレッド、もう 1 つは WriteNumber(1) を実行するスレッドです。つまり、1000 の 0 とスレッドが最終的にどのように実行されるかによって、さまざまな順序で画面に 1000 個の 1 が表示されます。

私が最終的に得たのは2000 2です。私が思いついた 2 つの可能な解決策は次のとおりです。明らかに明らかな何かを見逃しているか、変数 x を WriteNumber 関数に送信することで、値渡しではなく参照渡しを行っているため、スレッドは、関数が設定された時点ではなく、最新バージョンの x を使用して実行されます。ただし、C#ではデフォルトで変数が値渡しされ、パラメーターに「ref」が含まれている場合にのみ参照渡しされることを理解していました。

4

2 に答える 2

18

xラムダ式でキャプチャしています。xスレッドを開始する前に、 の値が2 に変更されます。ループで値のコピーを作成する必要があります。

for (int x = 0; x < 2; x++)
{
    int copy = x;
    threadQueue.Enqueue(new Thread(() => WriteNumber(copy)));
}

ラムダ式は変数をキャプチャします。WriteNumber 渡された値は値によって渡されますが、スレッドが開始されるまではまったく呼び出されませんx

ループ内でコピーを作成することにより、ループの各反復はcopy変数の独自の個別の「インスタンス」を取得し、それは値を変更ません...そのため、WriteNumber呼び出されるまでに、各copy変数はまだ同じ値をx持っていますその繰り返しのために。

于 2012-06-19T21:34:38.573 に答える
9

これは、ループの終了xに の値がアクセスされ、その時点までにがアクセスされるために発生します。2

変数のキャプチャを防ぐには、一時変数を使用する必要があります。

for (int x = 0; x < 2; x++)
{
    int tmp = x;
    threadQueue.Enqueue(new Thread(() => WriteNumber(tmp)));
}
于 2012-06-19T21:35:49.040 に答える