I’m just getting to know some of the new .NET concurrent collections like ConcurrentDictionary and ConcurrentQueue and I was running some tests to see what happens when I write parallel to the Queue.
So I ran this:
private static void ParallelWriteToQueue(Queue<int> queue)
{
Stopwatch sw = Stopwatch.StartNew();
Parallel.For(1,1000001,(i) => queue.Enqueue(i));
sw.Stop();
Console.WriteLine("Regular int Queue - " + queue.Count + " time" + sw.ElapsedMilliseconds);
}
And as I thought I got the next exception:
Source array was not long enough. Check srcIndex and length, and the array's lower bounds.
So this Queue can’t handle concurrent en-queues as predicted.
But, When I changed the type of the queue to string, there was no exception, and the result writes something like
Regular string Queue - 663209 time117
Which means that only about 663k were en-queued.
Why was there no exception?
What happened to all of the not en-queued items?
this is the same function with Queue
private static void ParallelWriteToQueue(Queue<string> queue)
{
Stopwatch sw = Stopwatch.StartNew();
Parallel.For(1, 100001, (i) => queue.Enqueue(i.ToString()));
sw.Stop();
Console.WriteLine("Regular string Queue - " + queue.Count + " time" + +sw.ElapsedMilliseconds);
}
Whether or not you get an exception has nothing to do with the type you put in the queue. It is non-deterministic, I can reproduce the exception for both types and I can reproduce the case without exception also for both types – without changes to the code.
Running the following snippet shows this:
The output is something like
Runs with exception: 96. Runs without: 4The reason is – as others already mentioned – that
Queueis not thread safe. What happens here is called “Race condition”.