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

35
我发现你可以调用Queue.Synchronize来获取一个线程安全的队列对象,但是在Queue<T>上却没有同样的方法。有人知道为什么吗?这看起来有点奇怪。
4个回答

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团队认为太多的开发人员误解了Synchronise的用途(在较小程度上是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可能已被另一个线程更改。
强制开发人员在整个操作周围使用显式的lock语句,意味着防止这种虚假的安全感。
正如Brian所提到的,删除SyncRoot部分是因为它主要是为了支持Synchronized而引入的,但也因为在许多情况下有更好的锁对象选择 - 大多数情况下,要么是Queue实例本身,要么是一个
private static object lockObjForQueueOperations = new object();

关于拥有队列实例的类...

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

正如他们所说,线程很难处理,让它看起来容易可能会带来危险。


我不同意你的建议。有趣的是,MSDN的锁定文档说:“通常,表达式将是这个”。http://msdn.microsoft.com/en-us/library/c5kehkcz%28VS.71%29.aspx - dvogel
2
是的,对于.NET 1.1文档他们搞错了,可以查看最新的.NET 4版本进行更正...http://msdn.microsoft.com/zh-cn/library/c5kehkcz(v=VS.100).aspx - Matt Ryan

7
你可能会发现并行计算技术预览值得一试;以下是由正在开发该技术的团队发布的博客文章,内容非常实用:枚举并发集合。虽然不完全相同,但它可能解决你更大的问题。(他们甚至使用了Queue<T>ConcurrentQueue<T>作为示例。)

6

0

我猜你指的是第二个问题是关于Queue<T>的吧。

我无法具体回答这个问题,除了IsSynchronized和SyncRoot属性(但不包括Synchronise()方法)是从ICollection接口继承而来的。没有任何泛型集合使用它们,而ICollection<T>接口也不包括SyncRoot。

至于为什么它没有被包含在内,我只能推测它们可能没有按照库设计者预期的方式使用,或者它们根本没有被足够地使用以证明在新的集合中保留它们的必要性。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接