Queue <t> .Enqueue(T)方法在单独使用时是否是线程安全的?</t>

时间:2012-08-24 14:03:59

标签: c# asynchronous thread-safety queue

如果我同时从多个线程中调用Enqueue(T)并等待这些线程完成,然后再调用Dequeue()或枚举队列,那么它是否是线程安全的?

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());
});

4 个答案:

答案 0 :(得分:14)

The documentation还声明此类型的实例成员线程安全(向下滚动到“线程安全”部分)。

文档还说明:

  

一个队列可以同时支持多个读者,只要   集合未被修改。

然而,这只是并发读取不会改变列表这一事实的副产品。 使类型“线程安全”。线程安全最好被认为是在定义类型的公共合同的所有操作中提供 true 支持(在这种情况下,线程安全也在改变列表中)

更多的诙谐:Enqueue的实现不包括任何线程同步或锁定原语:

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++;
}

所以我选择“不”。有ConcurrentQueue用于多线程支持。

答案 1 :(得分:4)

这很重要:如果文档没有说队列是线程安全的,那就不是。 (对于Queue,他们说它不是线程安全的。)

查看内部是一个弱测试:内部可能随时更改为非线程安全版本。

除非在特殊情况下,否则不要依赖未记录的财产。

答案 2 :(得分:1)

我认为这不是线程安全的,因为Queue不是线程安全的。您正在将相同的实例共享给不同的线程。

  

只要未修改集合,队列就可以同时支持多个阅读器。即便如此,通过集合枚举本质上不是一个线程安全的过程。为了在枚举期间保证线程安全,您可以在整个枚举期间锁定集合。要允许多个线程访问集合以进行读写,您必须实现自己的同步。   http://msdn.microsoft.com/en-us/library/7977ey2c.aspx

答案 3 :(得分:0)

  

此类型的公共静态(在Visual Basic中为Shared)成员是线程安全的。不保证任何实例成员都是线程安全的。

http://msdn.microsoft.com/en-us/library/7977ey2c.aspx

您需要实现自己的同步(即使用lock()),或使用ConcurrentQueue(System.Collections.Concurrent)。