c ++中的线程安全的生产者/消费者模式

时间:2015-06-11 08:17:58

标签: c++ design-patterns std producer-consumer

如何开发线程安全的生产者/消费者模式?

就我而言,生产者在一个线程中运行,而消费者在另一个线程上运行。

std :: deque是否可以安全用于此目的?

我可以在一个线程中将push_back推送到deque的后面,在另一个线程中推送push_front吗?

编辑1

就我而言,我知道std :: deque中的最大项目数(例如10)。有没有什么方法可以预先为项目保留足够的空间,所以在处理过程中,没有必要改变队列内存的大小,因此确保当我添加推送数据时,前端数据不会发生变化?

3 个答案:

答案 0 :(得分:2)

STL C ++容器不是线程安全的:如果您决定使用它们,则在推送/弹出元素时需要使用适当的同步(基本上是std::mutexstd::lock)。

或者你可以使用设计合理的容器(单一生产者 - 单一消费者队列应该符合你的需要),这里有一个例子:http://www.boost.org/doc/libs/1_58_0/doc/html/lockfree.html

编辑后

插件:

是的,SPSC队列基本上是一个环形缓冲区,最终满足您的需求。

答案 1 :(得分:1)

  

如何开发线程安全的生产者/消费者模式?

有几种方法,但使用locks and monitors相当容易掌握,并没有很多隐藏的警告。标准库包含std::unique_lockstd::lock_guardstd::condition_variable来实现模式。有关简单示例,请查看condition_variable的cppreference页面。

  

std :: deque是否可以安全用于此目的?

不安全。你需要同步。

  

我可以在一个线程中将push_back推送到deque的后面,在另一个线程中推送push_front吗?

当然,但你需要同步。当队列为空或只有一个元素时,存在竞争条件。此外,当队列已满或短缺时,如果您想限制它的大小。

答案 2 :(得分:0)

我认为您的意思是push_back()pop_front()

std::deque本身不是线程安全的。 您需要使用std::mutex序列化访问,以便消费者在生产者尝试推送时不会尝试弹出。

您还应该考虑如何处理以下内容:

  1. 如果deque在查找下一个项目时为空,消费者的行为如何?
  2. 如果它进入等待状态,那么当deque被添加到时,你需要生产者通知std::condition_variable。 您可能还需要处理程序终止,其中消费者正在等待双端队列并且程序终止。除非你正确地协调事情,否则它可能会“永远等待”。

    10项是'piffle',所以我不打扰预留空间。 std::deque会自动增长和缩小,因此在构建工作应用程序之前,不要再进行细粒度调整。

      

    过早优化是万恶之源。

    注意:目前尚不清楚如何限制队列大小,但是如果生产者填满队列,然后等待它清除,那么你需要更多的等待和条件以反过来的方式进行协调。