C ++ std :: set线程安全吗?

时间:2009-09-01 12:02:11

标签: c++ stl std stdset

我对std :: set的线程安全性有疑问。

据我所知,我可以遍历一个集合并添加/擦除成员,这不会使迭代器失效。

但请考虑以下情况:

  • 线程'A'迭代一组shared_ptr< Type>
  • 线程'B'偶尔会在此集合中添加项目。

程序运行时我遇到了段错误,我不确定为什么会这样。缺乏线程安全是什么原因?

6 个答案:

答案 0 :(得分:29)

STL没有内置线程支持,因此您必须扩展STL 使用您自己的同步机制编写代码以使用STL 多线程环境。

例如,请查看此处:link text

由于set是容器类,因此MSDN对容器的线程安全性进行了以下说明。

单个对象是从多个线程读取的线程安全的。例如,给定一个对象A,可以安全地从线程1和线程2同时读取A.

如果一个线程正在写入单个对象,则必须保护对相同或其他线程上该对象的所有读写操作。例如,给定一个对象A,如果线程1写入A,则必须阻止线程2读取或写入A。

即使另一个线程正在读取或写入同一类型的不同实例,也可以安全地读取和写入一个类型的实例。例如,给定相同类型的对象A和B,如果在线程1中写入A并且在线程2中读取B,则是安全的。

答案 1 :(得分:23)

Dinkumware STL-Documentation包含有关该主题的以下段落。它可能(如文中所示)对大多数实现都有效。

  

对于定义的容器对象   标准C ++库,例如STL   容器和模板的对象   class basic_string,这个   实施遵循广泛   采用SGI规定的做法   STL:

     

多个线程可以安全地读取同一个容器对象。 (有   nunprotected可变子对象   容器对象。)

     

两个线程可以安全地操作不同的容器对象   相同类型。 (没有   不受保护的共享静态对象   在容器类型中。)

     

您必须防止同时访问容器   对象,如果至少有一个线程   修改对象。 (显而易见的   同步原语,例如   Dinkum线程库中的那些,   不会被容器破坏   对象。)

     

因此,没有尝试确保   容器上的原子操作   对象是线程安全的;但它是   很容易制作共享容器   在线程安全的对象   适当的粒度级别。

答案 2 :(得分:10)

没有STL容器是线程安全的,因此std::set不是。

在你的情况下,问题甚至不是真正的线程安全性:你只是在多个线程之间共享一个对象(很好)并在一个线程中修改它(也很好)。但正如您已经说过的那样,修改容器会使其迭代器无效。这是发生在同一个线程还是不同的线程中是没有意义的,因为它仍然是相同的容器

D'哦! §23.1.2.8声明插入不会使迭代器无效。

答案 3 :(得分:2)

简单说明:如果线程A正在通过容器移动迭代器,那么它正在查看容器内部。如果线程B修改了容器(即使是一个不会使A具有的迭代器无效的操作),线程A也会遇到麻烦,因为B正在欺骗容器内部,可能使它们处于(暂时)无效状态。这会导致线程A崩溃。

问题不在于迭代器本身。当他们需要容器的数据结构时,为了找到你遇到麻烦的位置。

这很简单。

答案 4 :(得分:1)

是。处理这种情况的一种方法是让每个线程在访问相同的set对象之前锁定共享的互斥锁。确保使用RAII技术锁定和解锁互斥锁。

答案 5 :(得分:1)

执行插入可能导致向量重新分配其底层内存,而迭代器仍可能指向先前(但无效)的内存地址,从而导致段错误。