我为SFML写了一个线程渲染器,它将指针指向可绘制对象并将它们存储在向量中以绘制每一帧。开始向矢量添加对象并将对象移除到矢量将经常导致分段错误(SIGSEGV)。为了试图解决这个问题,我会添加需要删除/添加到队列中的对象,以便稍后移除(绘制框架之前)。这似乎解决了它,但最近我已经注意到,如果我一次添加多个对象(或者添加/删除它们足够快),我会得到相同的SIGSEGV。C++线程安全vector.erase
我应该在向量中添加/删除时使用锁吗?
我为SFML写了一个线程渲染器,它将指针指向可绘制对象并将它们存储在向量中以绘制每一帧。开始向矢量添加对象并将对象移除到矢量将经常导致分段错误(SIGSEGV)。为了试图解决这个问题,我会添加需要删除/添加到队列中的对象,以便稍后移除(绘制框架之前)。这似乎解决了它,但最近我已经注意到,如果我一次添加多个对象(或者添加/删除它们足够快),我会得到相同的SIGSEGV。C++线程安全vector.erase
我应该在向量中添加/删除时使用锁吗?
我应该在向量中添加/删除时使用锁吗?
是的。如果您同时使用来自两个线程的向量并重新分配,则后备分配可能会换出并释放到其他线程的后面。另一个线程将读取/写入释放的内存,或用于另一个无关分配的内存。
您需要了解线程安全性,以保证C++标准(以及可能的并发系统的C++ 2003的实现)给出。标准容器在以下意义上是线程安全的:
很多人误解容器的线程安全的意思,这些规则是由容器实现地税:他们都没有!遵守这些规则是你的责任。
这些不是,实际上不能由容器强加的原因是它们没有适合这个的接口。例如,考虑下面的琐碎一段代码:
if (!c.empty() {
auto value = c.back();
// do something with the read value
}
容器可以控制到empty()
和back()
接入到呼叫。然而,在这些调用之间,它必然需要释放任何类型的同步设施,即在线程尝试读取c.back()
时容器可能再次变空!基本上有两种方法来解决这个问题:
这两种策略都有它们的优点,标准库容器明显支持第一种样式,即当与至少一个修改容器的线程同时使用时,它们需要外部锁定。如果首先只有一个线程使用它们,它们不需要任何类型的锁定(无论是内部还是外部)。这实际上是他们设计的场景。为它们提供的线程安全保证已经到位,以确保没有内部工具不是线程安全的,比如每个对象迭代器对象或多线程共享的内存分配工具,而不是线程安全的,等等
要回答原始问题:是的,您需要使用外部同步,例如以互斥锁的形式,如果您在一个线程中修改容器并在另一个线程中读取它。
我认为一个静态锁就足够了。 –