【发布时间】:2010-09-11 13:11:45
【问题描述】:
我注意到您可以调用 Queue.Synchronize 来获取线程安全的队列对象,但同样的方法在 Queue
【问题讨论】:
标签: .net generics synchronization queue
我注意到您可以调用 Queue.Synchronize 来获取线程安全的队列对象,但同样的方法在 Queue
【问题讨论】:
标签: .net generics synchronization queue
更新 - 在 .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
关键问题是获得正确的锁定粒度,一些开发人员会天真地在“同步”集合上使用多个属性或方法,并认为他们的代码是线程安全的。 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,让它看起来很容易可能很危险。
【讨论】:
您可能会发现 Parallel CTP 值得一试;这里有一篇博客文章,来自将它放在一起的人,非常热门:
Enumerating Concurrent Collections
这并不完全相同,但它可能会解决您更大的问题。 (他们甚至使用Queue<T> 和ConcurrentQueue<T> 作为他们的例子。)
【讨论】:
现在有一个,在 .Net 4.0 中:
ConcurrentQueue<T>
在 System.Collections.Concurrent 中
【讨论】:
(我假设您的意思是 Queue
我无法具体回答这个问题,除了 IsSynchronized 和 SyncRoot 属性(但不是明确的 Synchronise())是从 ICollection 接口继承的。没有一个通用集合使用它,并且 ICollection
至于为什么不包含它,我只能推测它们没有按照图书馆设计者的预期方式使用,或者它们的使用不足以证明将它们保留在较新的馆藏中是合理的。
【讨论】: