ConcurrentQueue.IsEmpty需要内存屏障吗?

3
当研究IsEmpty时,我注意到MSDN上的这个内容:
“然而,由于该集合旨在同时访问,因此可能会有另一个线程在IsEmpty返回后修改集合,从而使结果无效。”
虽然这是正确的,但这是否也意味着ConcurrentQueue在检查队列是否为空时不使用读屏障呢?
我想编写一段代码,在另一个线程中检查并发队列是否为空。类似这样:
while (!queue.IsEmpty)
{
}

然而,如果ConcurrentQueue没有使用读取屏障,我认为我们需要添加自己的内存屏障以确保我们读取正确的数据,像这样:

Thread.MemoryBarrier();
while (!queue.IsEmpty)
{
    Thread.MemoryBarrier();
}

顺便说一句:这只是一个最简单的示例以说明这种情况,实际上还有更多的代码)。

我的观察正确吗?或者ConcurrentQueue处理了这个问题,第一种实现方式可以工作吗?(例如,我从'Concurrent'中期望的结果是什么?)

'Count'呢?我在MSDN上找不到答案...是同样的情况吗?


1
它是否使用内存屏障又有什么关系呢?当您读取返回的数据时,屏障已经成为历史,所有的赌注都无效了。 - spender
@spender 如果它不使用读取屏障,它可能会无限循环 - 在我看来这是非常糟糕的事情。 - atlaste
1个回答

6
不,它与内存屏障无关。问题在于,在您的测试之后,其他东西可能会插入或删除队列中的内容。
您真的不应该使用 IsEmpty。请改用 TryDequeue 或使用 BlockingCollection。
你真的不想开始编写代码,同时处理 IsEmpty 或 Count 来“锁定”队列。
(我现在几乎从不使用 ConcurrentQueue,因为 BlockingCollection 更好得多,尽管当然这取决于您要做什么。)

如果在对某个操作进行测试之前,您就要进行该操作,那么就容易出现并发问题。TryDequeue、AddOrUpdate等操作可以通过消除需要两阶段的测试/提交操作来解决这些问题。 - spender
2
现在我很少使用BlockingCollection,因为BufferBlock(以及TPL Dataflow的其他部分)要好得多;) - spender
@spender:我们仍然需要支持Windows Server 2003,因此我们不能使用.Net 4.5,所以BufferBlock对我们来说毫无用处。 :) 除非 - 有没有针对.Net 4的版本? - Matthew Watson
当然是的。没有await关键字,也不能使用新的TPL库等。 :( - Matthew Watson
1
正确的做法是不需要使用内存屏障。但同时,你也无法控制在检查了 IsEmpty 的返回值之后,在执行操作之前队列是否变为空或非空状态。 - Matthew Watson
显示剩余3条评论

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