If a Queue is syncronized:
var _item = Queue.Synchronized(new Queue());
can I call methods like Enqueue and Dequeue on it without using lock statements?
My current code is:
lock (_item.SyncRoot)
{
_item.Enqueue(开发者_如何学Goobj);
}
Can I thread-safely use:
_item.Enqueue(obj);
var item = _item.Dequeue();
The call to Enqueue
and the call to Dequeue
are thread safe.
However, your sample code is not:
Between the call to Enqueue
and the call to Dequeue
there could have been a thread switch. This means, that item
might be another instance than obj
or the call to Dequeue
throws an exception, because it now is empty.
To make your sample code thread safe, you still need to lock explicitly:
lock(_item.SyncRoot)
{
_item.Enqueue(obj);
var item = _item.Dequeue);
}
Only now it is guaranteed, that item
reference-equals obj
in all circumstances.
That is pretty much what SynchronizedQueue
does, but there is a problem... typically you need to check the .Count
and .Dequeue()
in one atomic unit - not check the .Count
(one unit) then .Dequeue()
(another unit) - you can't trust .Count
at all once the lock is surrendered, and .Dequeue()
will throw if another thread has stolen the work.
Maybe try ConcurrentQueue<T>
in 4.0 (with .TryDequeue()
), or use Queue<T>
and lock
.
From MSDN
To guarantee the thread safety of the Queue, all operations must be done through this wrapper only.
Enumerating through a collection is intrinsically not a thread-safe procedure. Even when a collection is synchronized, other threads can still modify the collection, which causes the enumerator to throw an exception. To guarantee thread safety during enumeration, you can either lock the collection during the entire enumeration or catch the exceptions resulting from changes made by other threads.
Just as John Skeet's answer suggests here, you might be better or using locking since enumerating might cause an exception.
Gregs answer also talks about what Marc mentions with the Count
not being thread safe.
精彩评论