我对std :: set的线程安全性有疑问。
据我所知,我可以遍历一个集合并添加/擦除成员,这不会使迭代器失效。
但请考虑以下情况:
程序运行时我遇到了段错误,我不确定为什么会这样。缺乏线程安全是什么原因?
答案 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)
执行插入可能导致向量重新分配其底层内存,而迭代器仍可能指向先前(但无效)的内存地址,从而导致段错误。