views:

446

answers:

4

A read operation on a 32 bit field is atomic. So if the queue holds object references the Queue.Peek method should be thread safe, right?

+6  A: 

No, you should still lock around each Peek() call.

Since Queue internally uses an Array, its instance methods are not thread safe, because array could be changed by a different thread at any time.

Peek() also checks for queue length to see if there are elements in the queue before returning the actual value, and some other thread might remove those elements before the method actually returns those values.

Groo
Correct, but it's not just the checking of queue length that makes `Peek` thread-unsafe. It's possible that your `Peek` call might execute halfway through an `Enqueue` or `Dequeue` on another thread.
LukeH
Yep, the underlying Array is also not thread safe, but this was supposed to be an example of a race condition.
Groo
+4  A: 

If you look at the implementation in .net reflector, it looks like this...

public virtual object Peek()
{
    if (this._size == 0)
    {
        throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_EmptyQueue"));
    }
    return this._array[this._head];
}

So no. Not thread safe.

Andrew Rollings
I was a bit reluctant to include Reflector code, I'm never 100% sure how legal it actually is. :) But I guess this thread explains it: http://stackoverflow.com/questions/378498/can-i-reflector-the-net-base-class-libraries-bcl.
Groo
meh :) (and meh to at least 15 characters)
Andrew Rollings
+16  A: 

No. And even if it were, that misses the point. Let's assume a thread safe peek for a moment. You typically end up writing code that does something kind of like this:

if (MyQueue.Peek() != null)
  var item = MyQueue.Dequeue();

That's a bug in multi-threaded code even if both Peek() and Dequeue() are thread safe, because you need to remember that the queue can change in between when you check with Peek() and when you act on the information it gives you with Dequeue(). You need to make sure you lock around both parts.

Joel Coehoorn
+1 this is the fundamentally important answer!
Daniel Earwicker
+2  A: 

It is not thread safe.

But to synchronize it you may find a ReaderWriterLockSlim to be the best. Only the Enqueue() and Dequeue() methods would require a write-lock. Peek() would only require a read-lock.

NathanE