将TryDequeue放入while循环中是否安全?

我之前没有使用过并发队列。

可以在while循环中使用如下所示的TryDequeue吗? 难道这不会永远陷入困境吗?

var cq = new ConcurrentQueue(); cq.Enqueue("test"); string retValue; while(!cq.TryDequeue(out retValue)) { // Maybe sleep? } //Do rest of code 

是的,根据文档是安全的,但它不是推荐的设计。

如果队列在第一次调用TryDequeue时为空,并且如果在该点之后没有其他线程在队列中推送数据(可能在N次尝试之后或超时之后打破),它可能会“永远陷入困境”。

ConcurrentQueue提供了一个IsEmpty成员来检查队列中是否有项目。 检查它比循环TryDequeue调用更有效(特别是如果队列通常为空)

可能想做的是:

 while(cq.IsEmpty()) { // Maybe sleep / wait / ... } if(cq.TryDequeue(out retValue)) { ... } 

编辑:如果最后一次调用返回false:另一个线程将该项目队列化。 如果你没有其他线程,这是安全的,如果你这样做,你应该使用while(TryDequeue)

它是安全的,因为循环在它已经拔出的项目之前实际上不会结束,并且如果队列有一个要取出的项目它将最终结束。 如果队列被另一个线程清空并且不再添加任何项目,那么循环当然不会结束。

除此之外,你所拥有的是一个繁忙的循环。 实际上应该始终避免这种情况。 要么你最终不断轮询队列要求更多的项目,浪费CPU时间和精力,或者你最终睡觉,因此一旦添加它就不会实际使用队列中的项目(即便如此,仍然浪费上下文切换的一些时间/精力只是为了轮询队列)。

如果你发现自己处于想要“等到有一件物品可供我”的位置,你应该做的是使用BlockingCollection 。 它专门用于包装各种类型的并发集合并阻塞,直到有可用的项目为止。 它允许您将代码更改为queue.Take()并使其更容易编写,从语义上说明您正在做什么,明确正确,明显更有效,以及完全安全。