2017-04-04 7 views
2

私はキューの中で質問したいと思います。# ConcurrentQueueが安全なスレッドであれば、なぜこのコードの結果は〜98 k? 何か問題がありますか?ConcurrentQueue C#、不正確な結果ですか?

class Program 
{ 
    static int sum = 0; 
    static ConcurrentQueue<int> queue = new ConcurrentQueue<int>(); 

    static void Main() 
    { 
     for (int i = 0; i < 100000; i++) 
     { 
      queue.Enqueue(1); 
     } 

     Task t1 = Task.Run(() => Calculate()); 
     Task t2 = Task.Run(() => Calculate()); 

     Task.WaitAll(t1, t2); 

     Console.WriteLine($"Sum = {sum}"); 
     Console.ReadKey(); 
    } 

    static void Calculate() 
    { 

     int result; 
     while (queue.TryDequeue(out result)) 
     { 
      sum += result; 
     } 
    } 
} 
+0

' sum + = result'はアトミック演算ではなく、両方のスレッドで同時に実行できます。 – Lee

答えて

2

その

sum += result; 

のこれは、スレッドセーフではありませんので。複数のスレッドが同時にこのLoCにヒットし、同じ値を割り当てることができます。

lockステートメント(他にも)で修正できます。

sum += result; 

アトミックではありません。

7

これが問題です。効果的です:

両方のスレッドが同時に中間線に達したらどうなると思いますか?

あなたはInterlocked.Addでこの問題を解決することができます

while (queue.TryDequeue(out result)) 
{ 
    Interlocked.Add(ref sum, result); 
} 

注意これはConcurrentQueueを使用してとは何の関係もないこと - あなたのループがちょうどあった場合は、同じものを参照してくださいね。

for (int i = 0; i < 50000; i++) 
{ 
    sum++; // Just as bad... 
} 
+0

ロックと連動して交換できますか? – tylkonachwile

+0

@ tylkonachwile:はい、それもうまくいくでしょう。 –

関連する問題