3

これは、ジョセフ・アルバハリの優れたC#5.0の一言で言えば本からのものです

彼の章の1つで、彼はこのコードブロックで競合状態について言及しています。上記の競合状態を生成する

_button.Click += (sender, args) =>
{
   _button.IsEnabled = false;
   Task.Run (() => Go());
};

void Go()
{
    for (int i = 1; i < 5; i++)
    {
        int result = GetPrimesCount (i * 1000000, 1000000);
        Dispatcher.BeginInvoke (new Action (() =>
       _results.Text += result + " primes between " + (i*1000000) + " and " + 
                                   ((i+1)*1000000-1) + Environment.NewLine));
    }

    Dispatcher.BeginInvoke (new Action (() => _button.IsEnabled = true));
}
4

2 に答える 2

3

@Sergeの答えに同意しません。問題を確認するために複数のスレッドは必要ありません。コードを元の形式で実行して、出力に注目してください。私にとっては次のようになり、ランダムになることもあります(最初の値を修正しました)。

1000000 primes between 5000000 and 5999999
1000000 primes between 5000000 and 5999999
1000000 primes between 5000000 and 5999999
1000000 primes between 5000000 and 5999999

最後の2つの値に注意してください。それらはすべて同じですが、に依存する必要がありますi。問題は、GUIスレッドがとにかくアクションを順番に実行するため、操作がアトミックではないということではありません。

これが発生する理由は、に渡されたラムダ関数が初期化の時点ではなく実行の時点でBeginInvokeの値を取得するため、実行されるまでにの最後の値がすべて表示されるためです。解決策は、次のようにパラメータとしてラムダに明示的に渡すことです。i ii

for (int i = 1; i < 5; i++)
{
    int result = 1000000;
    Dispatcher.BeginInvoke(new Action<int>(j =>
    results.Text += result + " primes between " + (j * 1000000) + " and " +
                              ((j + 1) * 1000000 - 1) + Environment.NewLine), i);
}
于 2012-09-23T07:26:06.110 に答える
2

この行はアトミックに計算されません:

_results.Text += result + " primes between " + (i*1000000) + " and " + ((i+1)*1000000-1) + Environment.NewLine));

したがって、同時に実行されている5つのスレッドから実行すると、さまざまな面白い結果が生成される可能性があります。

于 2012-09-23T00:20:23.150 に答える