ConcurrentQueue c#,结果不准确?

时间:2017-04-04 19:10:47

标签: c#

我想问一下c#中的队列 如果ConcurrentQueue是安全线程,为什么这段代码的结果是~98 k? 我有什么问题吗?

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;
        }
    }
}

2 个答案:

答案 0 :(得分: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...
}

答案 1 :(得分:2)

因为

sum += result;

这不是线程安全的。多个线程可以同时命中此LoC并分配相同的值。

您可以使用lock语句(以及其他方式)解决此问题。