got a quick question.
Do I have to use a concurrent queue if one thread is enqueuing and other is dequeuing? Is there any race condition/other risk when using regular container in this scenario (1 reader & 1 writer)?
got a quick question.
Do I have to use a concurrent queue if one thread is enqueuing and other is dequeuing? Is there any race condition/other risk when using regular container in this scenario (1 reader & 1 writer)?
With a ConcurrentQueue
you can safely call the methods Enqueue
and TryDequeue
from multiple threads in parallel. There is no race condition here. You could do it all day long 1,000,000 times per second, with no issues (assuming that you won't consume all the available memory at any moment doing that). There could be a race condition though if you would like to wait for an item to become available, if there is none. For example the consumer thread could run in a loop like this:
while (true)
{
if (!queue.IsEmpty)
{
queue.TryDequeue(out var item); // Race condition!
Process(item);
}
else
{
Thread.Sleep(50);
}
}
This code has a race condition between the calls to IsEmpty
and TryDequeue
. The queue could be emptied by another thread in the meanwhile. This race condition could be eliminated simply by removing the IsEmpty
check:
while (true)
{
if (queue.TryDequeue(out var item)) // Fixed
{
Process(item);
}
else
{
Thread.Sleep(50);
}
}
This is inefficient though. The thread will be doing unproductive loops, and when an item becomes available it will take it after a delay. Also notice that the queue has no way of notifying the thread that it has been completed, and will never have any more items again. Both of these problems are solved with the specialized BlockingCollection
class.
foreach (var item in blockingCollection.GetConsumingEnumerable())
{
Process(item);
}
The GetConsumingEnumerable
method ensures instant notification for either a new item, or for the completion of the collection.
The BlockingCollection
class has a drawback though. As its name suggests, it blocks the current thread during the waiting. If this is something that you would like to avoid, you can look here for a quick summary of the asynchronous alternatives.