views:

2674

answers:

3

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.

A: 

(I assume you mean Queue<T> for the second one.)

I can't specifically answer the question, except that the IsSynchronized and SyncRoot properties (but not Synchronise() explicitly) are inherited from the ICollection interface. None of the generic collections use this and the ICollection<T> interface does not include SyncRoot.

As to why it is not included, I can only speculate that they weren't being used either in the way intended by the library designers or they simply weren't being used enough to justify retaining them in the newer collections.

Zooba
+4  A: 

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.)

Domenic
+17  A: 

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:

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

Matt Ryan
I don't agree with your advice. It's interesting that MSDN's lock documentation says "Typically, expression will either be this" http://msdn.microsoft.com/en-us/library/c5kehkcz%28VS.71%29.aspx
Yeah they got it wrong for the .NET 1.1 doco, check out the latest .NET 4 version for the corrections... http://msdn.microsoft.com/en-us/library/c5kehkcz(v=VS.100).aspx
Matt Ryan