为什么在.NET中没有通用的同步队列?

我注意到你可以调用Queue.Synchronize来获得一个线程安全的队列对象,但是同样的方法在Queue <T>上是不可用的。 有谁知道为什么? 似乎有点怪异。

更新 – 在.NET 4中,现在是System.Collections.Concurrent中的ConcurrentQueue<T> ,如http://msdn.microsoft.com/zh-cn/library/dd267265.aspx中所述; 。 有趣的是,它的IsSynchronized方法(正确)返回false。

ConcurrentQueue<T>是一个完全彻底的重写,创build队列的副本枚举,并使用先进的无锁技术,如Interlocked.CompareExchange()Thread.SpinWait()

这个答案的其余部分仍然是相关的,因为它涉及到旧的Synchronize()和SyncRoot成员的消亡,以及为什么他们从API的angular度来说工作得不好。


根据Zooba的评论,BCL团队认为太多开发人员误解了Synchronize的用途(SyncRoot的程度较低)

几年前,Brian Grunkemeyer在BCL团队的博客上描述了这一点: http : //blogs.msdn.com/bclteam/archive/2005/03/15/396399.aspx

关键问题是获取锁的正确粒度,其中一些开发人员会天真地使用“同步”集合上的多个属性或方法,并相信他们的代码是线程安全的。 Brian以队列为例,

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

在调用Dequeue之前,开发人员不会意识到Count可能会被另一个线程所改变。

迫使开发人员在整个操作中使用明确的locking语句意味着防止这种错误的安全感。

正如Brian所提到的那样,删除SyncRoot的部分原因是它主要是为了支持Synchronized而引入的,但也因为在很多情况下锁对象有更好的select – 大多数情况下,Queue实例本身或

 private static object lockObjForQueueOperations = new object(); 

在拥有Queue实例的类上

后一种方法通常是最安全的,因为它避免了一些其他常见的陷阱:

  • 永远不要locking(这个)
  • 不要locking(string)或locking(typeof(A))

正如他们所说的, 线程很难 ,而且看起来很简单可能是危险的。

您可能会发现并行CTP值得检查; 这里有一些博客文章,这些博客是把这些内容放在一起的,非常有趣的:

枚举并发集合

这不是一回事,但它可以解决你的更大的问题。 (他们甚至使用Queue<T>ConcurrentQueue<T>作为例子。)

现在在.Net 4.0中有一个:

 ConcurrentQueue<T> 

在System.Collections.Concurrent中

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

(我假设你的意思是第二个队列<T>)。

除了IsSynchronized和SyncRoot属性(而不是显式的Synchronize())从ICollection接口inheritance外,我无法专门回答这个问题。 没有一个generics集合使用这个,ICollection <T>接口不包含SyncRoot。

至于为什么不包括在内,我只能推测,它们既没有被图书馆devise者所使用的方式使用,也没有被用来certificate它们被保留在新的馆藏中。