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

36 c++ stl std stdset

我有一个关于std :: set的线程安全性的问题.

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

但请考虑以下情况:

  • 线程'A'遍历一组shared_ptr <Type>
  • 线程'B'偶尔会将项目添加到此集合中.

程序运行时我经历过段错误,我不确定为什么会这样.缺乏线程安全的原因是什么?

Vai*_*hav 29

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

例如,看这里:链接文本

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

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

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

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

  • 实际上,您会发现创建包含std :: set的线程安全类更容易,而不是扩展集合本身.减少工作量. (8认同)
  • @Kieveli +1,但你必须小心不要在集合中提供后门(返回set迭代器),这可能意味着必须在set迭代器之上编写你自己的迭代器集,以便增量/减量是线程安全的.实现线程安全集和包装器都不是简单的任务...... (4认同)

RED*_*AIR 23

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

对于标准C++库中定义的容器对象,例如STL容器和模板类basic_string的对象,此实现遵循为SGI STL规定的广泛采用的实践:

多个线程可以安全地读取相同的容器对象.(容器对象中有nunprotected mutable子对象.)

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

如果至少有一个线程正在修改对象,则必须防止同时访问容器对象.(明显的同步原语,例如Dinkum线程库中的原语,不会被容器对象破坏.)

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


Kon*_*lph 11

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

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

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

  • @suszterpatt.插入可能不会使迭代器无效.但是,如果线程A是通过插入一半是一套有效的内部状态(它会插入时完成,但没有要求在任何其他点有效是有效).现在,如果你增加一个seprate线程的有效迭代器是迭代器与设定互动?如果是这样,那么结果可能是未定义的. (3认同)
  • ...即使迭代器没有失效,我也不相信插入和删除在两个线程使用时将集合保持在可用状态. (2认同)