为什么在.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中
(我假设你的意思是第二个队列<T>)。
除了IsSynchronized和SyncRoot属性(而不是显式的Synchronize())从ICollection接口inheritance外,我无法专门回答这个问题。 没有一个generics集合使用这个,ICollection <T>接口不包含SyncRoot。
至于为什么不包括在内,我只能推测,它们既没有被图书馆devise者所使用的方式使用,也没有被用来certificate它们被保留在新的馆藏中。