简体   繁体   English

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

[英]Is the C++ std::set thread-safe?

I've a question about the thread safety of std::set. 我有一个关于std :: set的线程安全性的问题。

As far as I know I can iterate over a set and add/erase members and that doesn't invalidate the iterators. 据我所知,我可以遍历一个集合并添加/擦除成员,这不会使迭代器无效。

But consider following scenario: 但请考虑以下情况:

  • thread 'A' iterates over a set of shared_ptr<Type> 线程'A'遍历一组shared_ptr <Type>
  • thread 'B' occasionally adds items to this set. 线程'B'偶尔会将项目添加到此集合中。

I've experienced segfaults as the program runs and I'm not sure why this happens. 程序运行时我经历过段错误,我不确定为什么会这样。 Is lack of thread safety the cause? 缺乏线程安全的原因是什么?

STL has no built in thread support, so you'll have to extend the STL code with your own synchronization mechanisms to use STL in a multithreaded environment. STL没有内置线程支持,因此您必须使用自己的同步机制扩展STL代码,以便在多线程环境中使用STL。

For example look here: link text 例如,看这里: 链接文本

Since set is a container class MSDN has following to say about the thread safety of the containers. 由于set是一个容器类,因此MSDN对容器的线程安全性进行了以下说明。

A single object is thread safe for reading from multiple threads. 单个对象对于从多个线程读取是线程安全的。 For example, given an object A, it is safe to read A from thread 1 and from thread 2 simultaneously. 例如,给定对象A,可以安全地从线程1和线程2同时读取A.

If a single object is being written to by one thread, then all reads and writes to that object on the same or other threads must be protected. 如果一个线程正在写入单个对象,则必须保护对相同或其他线程上该对象的所有读写操作。 For example, given an object A, if thread 1 is writing to A, then thread 2 must be prevented from reading from or writing to A. 例如,给定对象A,如果线程1写入A,则必须阻止线程2读取或写入A.

It is safe to read and write to one instance of a type even if another thread is reading or writing to a different instance of the same type. 即使另一个线程正在读取或写入同一类型的不同实例,也可以安全地读取和写入一个类型的实例。 For example, given objects A and B of the same type, it is safe if A is being written in thread 1 and B is being read in thread 2. 例如,给定相同类型的对象A和B,如果在线程1中写入A并且在线程2中读取B,则是安全的。

The Dinkumware STL-Documentation contains the follwing paragraph about that topic. Dinkumware STL-Documentation包含有关该主题的以下段落。 Its probably (as indicated in the text) valid for most implementations. 它可能(如文中所示)对大多数实现都有效。

For the container objects defined in the Standard C++ Library, such as STL Containers and objects of template class basic_string, this implementation follows the widely adopted practices spelled out for SGI STL: 对于标准C ++库中定义的容器对象,例如STL容器和模板类basic_string的对象,此实现遵循为SGI STL规定的广泛采用的实践:

Multiple threads can safely read the same container object. 多个线程可以安全地读取相同的容器对象。 (There are nunprotected mutable subobjects within a container object.) (容器对象中有nunprotected mutable子对象。)

Two threads can safely manipulate different container objects of the same type. 两个线程可以安全地操作相同类型的不同容器对象。 (There are no unprotected shared static objects within a container type.) (容器类型中没有不受保护的共享静态对象。)

You must protect against simultaneous access to a container object if at least one thread is modifying the object. 如果至少有一个线程正在修改对象,则必须防止同时访问容器对象。 (The obvious synchronization primitives, such as those in the Dinkum Threads Library, will not be subverted by the container object.) (明显的同步原语,例如Dinkum线程库中的原语,不会被容器对象破坏。)

Thus, no attempt is made to ensure that atomic operations on container objects are thread safe; 因此,没有尝试确保容器对象上的原子操作是线程安全的; but it is easy enough to make shared container objects that are thread safe at the appropriate level of granularity. 但是,在适当的粒度级别上创建线程安全的共享容器对象非常容易。

None of the STL containers is thread safe, so std::set in particular isn't. 没有STL容器是线程安全的,因此特别是std::set不是。

In your case, the issue isn't even really thread safety, though: You simply share an object across multiple threads (fine) and modify it in one thread (fine as well). 在您的情况下,问题甚至不是真正的线程安全,但是:您只需跨多个线程共享一个对象(很好)并在一个线程中修改它(也很好)。 But as you've already said, modifying the container invalidates its iterators. 但正如您已经说过的那样,修改容器会使其迭代器无效。 Whether this happens in the same thread or in a different thread is of no consequence since it's still the same container . 无论是在同一个线程中还是在不同的线程中发生这种情况都没有任何意义,因为它仍然是同一个容器

D'oh! D'哦! §23.1.2.8 states that inserting doesn't invalidate iterators. §23.1.2.8声明插入不会使迭代器无效。

Simple explanation: If thread A is moving iterators through the container, it's looking at container internals. 简单的解释:如果线程A正在通过容器移动迭代器,那么它正在查看容器内部。 If thread B modifies the container (even an operation that doesn't invalidate the iterator that A has), thread A can run into trouble because B is fooling with the container internals, possibly having them in a (temporarily) invalid state. 如果线程B修改容器(即使是一个不会使A具有的迭代器无效的操作),线程A也会遇到麻烦,因为B正在欺骗容器内部,可能使它们处于(暂时)无效状态。 This causes crashes in thread A. 这会导致线程A崩溃。

The problem ISN'T the iterators themselves. 问题不是迭代器本身。 It when they need the container's data structures in order to find the position that you get into trouble. 当他们需要容器的数据结构时,为了找到你遇到麻烦的位置。

Simple as that. 就那么简单。

Yes. 是。 One way to handle this situation is to have each thread lock a shared mutex before accessing the same set object. 处理这种情况的一种方法是让每个线程在访问相同的set对象之前锁定共享的互斥锁。 Make sure you use RAII techniques to lock and unlock the mutex. 确保使用RAII技术锁定和解锁互斥锁。

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

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

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