如果我同时从多个线程中调用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());
});
答案 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)。