C ++线程安全vector.erase

时间:2012-01-22 06:38:33

标签: c++ multithreading vector thread-safety

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

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

2 个答案:

答案 0 :(得分:3)

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

  1. 可以让多个并发线程读取同一个容器。
  2. 如果有一个线程修改容器,则不应该有并发线程读取或写入同一个容器。
  3. 不同的容器彼此独立。
  4. 许多人误解容器的线程安全意味着这些规则是由容器实现强加的:它们不是!遵守这些规则是你的责任。

    这些不是,实际上不能由容器施加的原因是它们没有适合这种情况的界面。例如,考虑以下一些简单的代码:

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

    容器可以控制对empty()back()的调用的访问权限。但是,在这些调用之间,它必然需要释放任何类型的同步工具,即在线程尝试读取c.back()时,容器可能再次为空!基本上有两种方法可以解决这个问题:

    1. 如果并发线程可能正在更改容器以跨越以某种形式相互依赖的整个访问范围,则需要使用外部锁定。
    2. 您将容器的界面更改为monitors。然而,容器界面根本不适合在这个方向上改变,因为监视器基本上只支持“发射”和“忘记”。接口风格。
    3. 两种策略都有其优点,并且标准库容器明显支持第一种样式,即当与至少一个修改容器的线程的潜力同时使用时,它们需要外部锁定。如果首先只有一个线程使用它们,它们就不需要任何类型的锁定(内部或外部)。这实际上是他们设计的场景。为它们提供的线程安全保证是为了保证没有使用不是线程安全的内部工具,比如每个对象迭代器对象或多个线程共享的内存分配工具,而不是线程安全的,等等

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

答案 1 :(得分:1)

  

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

是。如果您同时使用来自两个线程的向量并重新分配,则可以交换支持分配并释放在另一个线程的脚后面。另一个线程将读取/写入释放的内存,或者用于另一个不相关分配的内存。