0

有一个快速的问题。

如果一个线程正在排队而另一个正在出队,我是否必须使用并发队列?在这种情况下(1 位读者和 1 位作者)使用常规容器时是否存在任何竞争条件/其他风险?

4

1 回答 1

3

使用 a您可以安全地从多个线程并行ConcurrentQueue调用方法。这里没有竞争条件。您可以一整天每秒执行 1,000,000 次,没有任何问题(假设您不会在任何时候消耗所有可用内存)。但是,如果您想等待某个项目可用(如果没有),则可能存在竞争条件。例如,消费者线程可以像这样在循环中运行:EnqueueTryDequeue

while (true)
{
    if (!queue.IsEmpty)
    {
        queue.TryDequeue(out var item); // Race condition!
        Process(item);
    }
    else
    {
        Thread.Sleep(50);
    }
}

IsEmpty此代码在对和的调用之间存在竞争条件TryDequeue。同时,队列可能被另一个线程清空。只需删除IsEmpty检查即可消除这种竞争条件:

while (true)
{
    if (queue.TryDequeue(out var item)) // Fixed
    {
        Process(item);
    }
    else
    {
        Thread.Sleep(50);
    }
}

这虽然效率低下。该线程将执行非生产性循环,当一个项目可用时,它将在延迟后使用它。另请注意,队列无法通知线程它已完成,并且永远不会再有任何项目。这两个问题都可以通过专门的BlockingCollection课程来解决。

foreach (var item in blockingCollection.GetConsumingEnumerable())
{
    Process(item);
}

GetConsumingEnumerable方法确保即时通知新项目或收集完成。

但是这个BlockingCollection类有一个缺点。顾名思义,它在等待期间阻塞当前线程。如果这是您想避免的事情,您可以在此处查看异步替代方案的快速摘要。

于 2020-04-08T20:52:33.457 回答