繁体   English   中英

C ++线程安全vector.erase

[英]C++ Thread safe vector.erase

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

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

您需要了解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. 您将容器的界面更改为监视器 但是,容器接口根本不适合朝这个方向更改,因为监视器本质上仅支持“即发即弃”风格的接口。

两种策略都有其优势,并且标准库容器显然支持第一种样式,即,在同时使用时需要外部锁定,并且可能至少有一个线程修改该容器。 如果一开始只使用一个线程,则它们不需要任何类型的锁定(内部或外部)。 这实际上是他们设计的方案。 为它们提供的线程安全性保证是适当的,以确保没有使用不是线程安全的内部设施,例如每个对象迭代器对象或由多个线程共享但不具有线程安全性的内存分配设施,等等。 。

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

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

是。 如果您同时使用两个线程中的向量并重新分配,则备用分配可能会换出并在另一个线程的脚后释放。 另一个线程将读取/写入释放的内存,或正在使用的内存用于另一个不相关的分配。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM