STL容器生产者/消费者模式的线程安全性

时间:2012-06-01 13:31:55

标签: c++ multithreading stl race-condition

我打算做以下事情:

存储要使用的预构建对象的双端队列。主线程可能会在这里和那里使用这些对象。我有另一个用于日志记录的垃圾线程和其他不是时间关键但昂贵的东西。当预构建的对象运行不足时,我会在junky线程中重新填充它们。

现在我的问题是,这里会有竞争条件吗?从技术上讲,一个线程正在从前面消耗对象,另一个线程正在将对象推入后面。只要我不让大小降到零,它应该没问题。我唯一关心的是这个双端队列的“大小”。它们是否在STL容器中存储整数“大小”变量?应该修改大小变量引入竞争条件?

解决这个问题的最佳方法是什么?我真的不想使用锁,因为主线程对性能至关重要(我首先预先构建这些对象的原因!)

4 个答案:

答案 0 :(得分:8)

STL容器不是线程安全的,期间,不要玩这个。具体来说,deque元素通常存储在一个短数组链中,并且当使用deque操作时链将被修改,因此存在很多搞乱的空间。

答案 1 :(得分:4)

另一个选择是有2个deques,一个用于读取另一个用于写入。主线程读取,另一个写入。当读取双端队列为空时,切换deques(只移动2个指针),这将涉及锁定,但只是偶尔。

消费者线程会驱动交换机,因此切换时 需要锁定。如果在写入过程中发生切换,生产者线程将需要锁定每次写入,但正如您所提到的那样,消费者对性能要求不高,所以不用担心。

你提出的关于没有锁的建议确实很危险,正如其他人所说。

答案 2 :(得分:1)

正如@sharptooth所提到的,STL容器不是线程安全的。您使用的是支持C ++ 11的编译器吗?如果是这样,您可以使用原子类型实现无锁队列。否则,您需要使用汇编程序进行比较和交换,或使用特定于平台的API(请参阅here)。请参阅this question以获取有关如何执行此操作的信息。

我要强调的是,在使用标准线程同步时应该测量性能,看看是否确实需要无锁技术。

答案 3 :(得分:0)

即使非空deque,也会有数据竞争。

您必须通过锁保护对deque的所有访问(不仅仅是写入),或者在多线程环境中使用专门为消费者 - 生产者模型设计的队列(例如Microsoft的{{1} })。