我注意到您可以调用Queue.Synchronize来获取线程安全的队列对象,但Queue
更新 - 在.NET 4中,现在存在ConcurrentQueue
System.Collections.Concurrent,如此处所述http://msdn.microsoft.com/en-us/library/dd267265.aspx.有趣的是,它的IsSynchronized方法(正确地)返回false.
ConcurrentQueue
是一个完整的重写,创建要枚举的队列的副本,并使用像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
关键问题是围绕锁获得正确的粒度,一些开发人员会在"同步"集合上天真地使用多个属性或方法,并相信他们的代码是线程安全的.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();
在拥有Queue实例的类上...
后一种方法通常是最安全的,因为它避免了一些其他常见的陷阱:
永远不要锁(这个)
不要锁定(字符串)或锁定(typeof(A))
正如他们所说,线程很难,让它看起来很容易也很危险.
你可能会发现Parallel CTP值得一试; 这是一个博客文章,来自那些把它放在一起的人们非常热门话题:
枚举并发集合
这不是一回事,但它可能会解决你更大的问题.(他们甚至使用Queue
对比ConcurrentQueue
作为他们的榜样.)
现在有一个,在.Net 4.0中:
ConcurrentQueue
在System.Collections.Concurrent中
http://msdn.microsoft.com/en-us/library/dd267265.aspx