对32位字段的读操作是原子的。因此,如果队列持有对象引用,Queue.Peek方法应该是线程安全的,对吗?
答案 0 :(得分:18)
没有。即便如此,也忽略了这一点。让我们假设一个线程安全的窥视片刻。您通常最终会编写执行类似这样的代码:
if (MyQueue.Peek() != null)
var item = MyQueue.Dequeue();
这是多线程代码中的一个错误,即使Peek()
和Dequeue()
本身都是线程安全的,因为您需要记住,当您使用Peek()检查时,队列之间可以发生更改当你对信息采取行动时,它会给你Dequeue()。您需要确保锁定两个部分。
答案 1 :(得分:7)
不,你仍然应该锁定每个Peek()
电话。
由于Queue内部使用一个Array,因此它的实例方法不是线程安全的,因为数组可以随时由另一个线程更改。
Peek()
还检查队列长度,以便在返回实际值之前查看队列中是否有元素,而其他一些线程可能会在方法实际返回这些值之前删除这些元素。
答案 2 :(得分:4)
如果你看看.net反射器中的实现,它看起来像这样......
public virtual object Peek()
{
if (this._size == 0)
{
throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_EmptyQueue"));
}
return this._array[this._head];
}
所以没有。不是线程安全的。
答案 3 :(得分:2)
它不是线程安全的。
但要同步它,您可能会发现ReaderWriterLockSlim
是最好的。只有Enqueue()
和Dequeue()
方法才需要写锁定。 Peek()
只需要一个读锁定。