2012-01-22 98 views
1

我为SFML写了一个线程渲染器,它将指针指向可绘制对象并将它们存储在向量中以绘制每一帧。开始向矢量添加对象并将对象移除到矢量将经常导致分段错误(SIGSEGV)。为了试图解决这个问题,我会添加需要删除/添加到队列中的对象,以便稍后移除(绘制框架之前)。这似乎解决了它,但最近我已经注意到,如果我一次添加多个对象(或者添加/删除它们足够快),我会得到相同的SIGSEGV。C++线程安全vector.erase

我应该在向量中添加/删除时使用锁吗?

+0

我认为一个静态锁就足够了。 –

回答

1

我应该在向量中添加/删除时使用锁吗?

是的。如果您同时使用来自两个线程的向量并重新分配,则后备分配可能会换出并释放到其他线程的后面。另一个线程将读取/写入释放的内存,或用于另一个无关分配的内存。

2

您需要了解线程安全性,以保证C++标准(以及可能的并发系统的C++ 2003的实现)给出。标准容器在以下意义上是线程安全的:

  1. 可以有多个并发线程读取同一个容器。
  2. 如果有一个线程修改一个容器,那么不应该有并发线程读取或写入同一个容器。
  3. 不同的容器是相互独立的。

很多人误解容器的线程安全的意思,这些规则是由容器实现地税:他们都没有!遵守这些规则是你的责任。

这些不是,实际上不能由容器强加的原因是它们没有适合这个的接口。例如,考虑下面的琐碎一段代码:

if (!c.empty() { 
    auto value = c.back(); 
    // do something with the read value 
} 

容器可以控制到empty()back()接入到呼叫。然而,在这些调用之间,它必然需要释放任何类型的同步设施,即在线程尝试读取c.back()时容器可能再次变空!基本上有两种方法来解决这个问题:

  1. 您需要使用外部锁定,如果有可能的是并发线程可改变容器跨越这是某种形式的相互依存访问的整个范围。
  2. 您将容器的接口更改为monitors。但是,容器接口并不适合在这个方向上进行改变,因为监视器基本上只支持“火和忘”式的接口。

这两种策略都有它们的优点,标准库容器明显支持第一种样式,即当与至少一个修改容器的线程同时使用时,它们需要外部锁定。如果首先只有一个线程使用它们,它们不需要任何类型的锁定(无论是内部还是外部)。这实际上是他们设计的场景。为它们提供的线程安全保证已经到位,以确保没有内部工具不是线程安全的,比如每个对象迭代器对象或多线程共享的内存分配工具,而不是线程安全的,等等

要回答原始问题:是的,您需要使用外部同步,例如以互斥锁的形式,如果您在一个线程中修改容器并在另一个线程中读取它。