ConcurrentQueue c#,结果不准确?

tyl*_*ile 2 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;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

Jon*_*eet 7

这就是问题:

sum += result;
Run Code Online (Sandbox Code Playgroud)

那不是原子的.这是有效的:

var tmp = sum;
tmp += result;
sum = tmp;
Run Code Online (Sandbox Code Playgroud)

如果你的两个线程同时到达中间线,你认为会发生什么?

你可以解决这个问题Interlocked.Add:

while (queue.TryDequeue(out result))
{
    Interlocked.Add(ref sum, result);
}
Run Code Online (Sandbox Code Playgroud)

请注意,这与使用无关ConcurrentQueue- 如果您的循环刚刚出现,您会看到同样的事情:

for (int i = 0; i < 50000; i++)
{
    sum++; // Just as bad...
}
Run Code Online (Sandbox Code Playgroud)