Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is there no generic synchronized queue in .NET?

I noticed that you can call Queue.Synchronize to get a thread-safe queue object, but the same method isn't available on Queue<T>. Does anyone know why? Seems kind of weird.

like image 563
skb Avatar asked Sep 20 '08 04:09

skb


3 Answers

Update - in .NET 4, there now is ConcurrentQueue<T> in System.Collections.Concurrent, as documented here http://msdn.microsoft.com/en-us/library/dd267265.aspx. It's interesting to note that its IsSynchronized method (rightly) returns false.

ConcurrentQueue<T> is a complete ground up rewrite, creating copies of the queue to enumerate, and using advanced no-lock techniques like Interlocked.CompareExchange() and Thread.SpinWait().

The rest of this answer is still relevant insofar as it relates to the demise of the old Synchronize() and SyncRoot members, and why they didn't work very well from an API perspective.


As per Zooba's comment, the BCL team decided that too many developers were misunderstanding the purpose of Synchronise (and to a lesser extent, SyncRoot)

Brian Grunkemeyer described this on the BCL team blog a couple of years back: http://blogs.msdn.com/bclteam/archive/2005/03/15/396399.aspx

The key issue is getting the correct granularity around locks, where some developers would naively use multiple properties or methods on a "synchronized" collection and believe their code to be thread safe. Brian uses Queue as his example,

if (queue.Count > 0) {     object obj = null;     try {         obj = queue.Dequeue(); 

Developers wouldn't realize that Count could be changed by another thread before Dequeue was invoked.

Forcing developers to use an explicit lock statement around the whole operation means preventing this false sense of security.

As Brian mentions, the removal of SyncRoot was partly because it had mainly been introduced to support Synchronized, but also because in many cases there is a better choice of lock object - most of the time, either the Queue instance itself, or a

private static object lockObjForQueueOperations = new object(); 

on the class owning the instance of the Queue...

This latter approach is usually safest as it avoids some other common traps:

  • Never lock(this)
  • Don't lock(string) or lock(typeof(A))

As they say, threading is hard, and making it seem easy can be dangerous.

like image 155
Matt Ryan Avatar answered Oct 29 '22 00:10

Matt Ryan


You might find the Parallel CTP worth checking out; here's a blog entry from the guys who are putting it together that's pretty topical:

Enumerating Concurrent Collections

It's not quite the same thing, but it might solve your bigger problem. (They even use Queue<T> versus ConcurrentQueue<T> as their example.)

like image 27
Domenic Avatar answered Oct 28 '22 23:10

Domenic


There is one now, in .Net 4.0:

ConcurrentQueue<T> 

in System.Collections.Concurrent

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

like image 43
Shane Castle Avatar answered Oct 29 '22 00:10

Shane Castle