Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is Queue<T>.Enqueue(T) method thread-safe when it is used alone?

Would it be thread-safe if I solely call Enqueue(T) from multiple threads simultaneously and wait for those threads to complete before calling Dequeue() or enumerating the queue?

var queue = new Queue<int>();
Action enqueue = () =>
{
    for (int i = 0; i < 100000; i++)
        queue.Enqueue(i);
};

var tasks = new[]
{
    new Task(enqueue),
    new Task(enqueue),
    new Task(enqueue)
};
foreach (var task in tasks)
    task.Start();

Task.Factory.ContinueWhenAll(tasks, t =>
{
    while (queue.Count > 0)
        Console.WriteLine(queue.Dequeue());
});
like image 584
Şafak Gür Avatar asked Aug 24 '12 14:08

Şafak Gür


People also ask

Are queues thread-safe?

The Queue module provides a FIFO implementation suitable for multi-threaded programming. It can be used to pass messages or other data between producer and consumer threads safely.

Are methods thread-safe?

First of all, the answer is NO. The method is not thread-safe, because the counter++ operation is not atomic, which means it consists more than one atomic operations. In this case, one is accessing value and the other is increasing the value by one.

Are queues thread-safe C#?

C# Queues can support multiple readers simultaneously. However, even when a collection is synchronized, it can still be modified by other threads, which will cause the enumerator to throw an exception. Generally, enumerating through a collection is not considered a thread-safe procedure.


1 Answers

The documentation also states that instance members of this type are not thread safe (scroll down to the Thread Safety section).

The documentation also states:

A Queue can support multiple readers concurrently, as long as the collection is not modified.

However, this is just a by-product of the fact that concurrent reading does not mutate the list. It does not make the type "thread-safe". Thread-safety is best thought of as offering true support across all actions that define the public contract of the type (in this case, thread-safety in mutating the list also).

More tongue-in-cheek: the implementation of Enqueue doesn't include any thread synchronisation or locking primitives:

public void Enqueue(T item)
{
    if (this._size == this._array.Length)
    {
        int num = (int)((long)this._array.Length * 200L / 100L);
        if (num < this._array.Length + 4)
        {
            num = this._array.Length + 4;
        }
        this.SetCapacity(num);
    }
    this._array[this._tail] = item;
    this._tail = (this._tail + 1) % this._array.Length;
    this._size++;
    this._version++;
}

So I'm going with "no". There is ConcurrentQueue for multi-threaded support.

like image 169
Adam Houldsworth Avatar answered Oct 12 '22 23:10

Adam Houldsworth