2017-04-04 35 views
2

我想问一下关于c#队列的问题# 如果ConcurrentQueue是安全线程,为什么这个代码的结果是〜98k? 我有什么问题吗?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声明(以及其他方式)修复此问题。

7

这就是问题所在:

sum += result; 

这不是原子。这是有效的:

var tmp = sum; 
tmp += result; 
sum = tmp; 

你觉得如果两个你的线程的到达,同时中间线会怎样呢?

您可以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:是的,那也可以。 –