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

skb*_*skb 35 .net generics queue synchronization

我注意到您可以调用Queue.Synchronize来获取线程安全的队列对象,但Queue <T>上没有相同的方法.有谁知道为什么?看起来有点奇怪.

Mat*_*yan 53

更新 - 在.NET 4中,现在存在ConcurrentQueue<T>System.Collections.Concurrent,如此处所述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();
Run Code Online (Sandbox Code Playgroud)

在调用Dequeue之前,开发人员不会意识到Count可以被另一个线程更改.

强制开发人员在整个操作周围使用显式锁定语句意味着防止这种错误的安全感.

正如Brian所提到的,删除SyncRoot部分是因为它主要是为了支持Synchronized而引入的,但也因为在很多情况下锁定对象有更好的选择 - 大多数时候,无论是Queue实例本身,还是

private static object lockObjForQueueOperations = new object();
Run Code Online (Sandbox Code Playgroud)

在拥有Queue实例的类上...

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

正如他们所说,线程很难,让它看起来很容易也很危险.

  • 是的,他们为.NET 1.1 doco弄错了,请查看最新的.NET 4版本以进行更正... http://msdn.microsoft.com/en-us/library/c5kehkcz(v=VS.100)的.aspx (2认同)

Dom*_*nic 7

你可能会发现Parallel CTP值得一试; 这是一个博客文章,来自那些把它放在一起的人们非常热门话题:

枚举并发集合

这不是一回事,但它可能会解决你更大的问题.(他们甚至使用Queue<T>对比ConcurrentQueue<T>作为他们的榜样.)


Sha*_*tle 6

现在有一个,在.Net 4.0中:

ConcurrentQueue<T> 
Run Code Online (Sandbox Code Playgroud)

在System.Collections.Concurrent中

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