我想问一下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;
}
}
}
答案 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
语句(以及其他方式)解决此问题。