我注意到您可以调用Queue.Synchronize来获取线程安全的队列对象,但Queue< T>上没有相同的方法。有谁知道为什么?看起来有点奇怪。
答案 0 :(得分:53)
更新 - 在.NET 4中,System.Collections.Concurrent中现在有ConcurrentQueue<T>
,如http://msdn.microsoft.com/en-us/library/dd267265.aspx所述。有趣的是,它的IsSynchronized方法(正确地)返回false。
ConcurrentQueue<T>
是一个完整的重写,创建要枚举的队列副本,并使用Interlocked.CompareExchange()
和Thread.SpinWait()
等高级无锁技术。
这个答案的其余部分仍然是相关的,因为它与旧的Synchronize()和SyncRoot成员的消亡有关,以及为什么它们从API的角度来看不能很好地工作。
根据Zooba的评论,BCL团队认为太多开发人员误解了Synchronize(以及较小程度上的SyncRoot)的目的
Brian Grunkemeyer几年前在BCL团队博客上描述了这一点: http://blogs.msdn.com/bclteam/archive/2005/03/15/396399.aspx
关键问题是围绕锁获得正确的粒度,一些开发人员会天真地在“synchronized”集合上使用多个属性或方法,并相信他们的代码是线程安全的。 Brian以Queue为例,
if (queue.Count > 0) {
object obj = null;
try {
obj = queue.Dequeue();
在调用Dequeue之前,开发人员不会意识到Count可以被另一个线程更改。
强制开发人员在整个操作周围使用显式锁定语句意味着防止这种错误的安全感。
正如Brian所提到的,删除SyncRoot部分是因为它主要是为了支持Synchronized而引入的,但也因为在很多情况下可以更好地选择锁定对象 - 大部分时间都是Queue实例本身,或者
private static object lockObjForQueueOperations = new object();
拥有队列实例的类......
后一种方法通常是最安全的,因为它避免了其他一些常见的陷阱:
正如他们所说,threading is hard,让它看似简单可能很危险。
答案 1 :(得分:7)
你可能会发现并行CTP值得一试;这是一个博客文章,来自那些把它放在一起非常热门的人:
Enumerating Concurrent Collections
这不是一回事,但它可能会解决你更大的问题。 (他们甚至使用Queue<T>
与ConcurrentQueue<T>
作为示例。)
答案 2 :(得分:6)
现在有一个,在.Net 4.0中:
ConcurrentQueue<T>
System.Collections.Concurrent中的
答案 3 :(得分:0)
(我假设您的意思是第二个队列&lt; T&gt;。)
我不能专门回答这个问题,除了从ICollection接口继承了IsSynchronized和SyncRoot属性(但不是显式的Synchronize())。通用集合中没有一个使用此和ICollection&lt; T&gt;。界面不包括SyncRoot。
至于为什么不包括它,我只能推测它们没有按照图书馆设计者的预期方式使用,或者它们的使用不足以证明在新版集合中保留它们的合理性。 / p>