C++ std::set 线程安全吗?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1362110/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Is the C++ std::set thread-safe?
提问by
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>
- thread 'B' occasionally adds items to this set.
- 线程 'A' 遍历一组 shared_ptr<Type>
- 线程 'B' 偶尔会向该集合中添加项目。
I've experienced segfaults as the program runs and I'm not sure why this happens. Is lack of thread safety the cause?
我在程序运行时遇到了段错误,但我不确定为什么会发生这种情况。缺乏线程安全是原因吗?
回答by Vaibhav
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,如果 A 在线程 1 中写入而 B 在线程 2 中读取,则是安全的。
回答by RED SOFT ADAIR
The Dinkumware STL-Documentation contains the follwing paragraph about that topic. Its probably (as indicated in the text) valid for most implementations.
Dinkumware STL 文档包含有关该主题的以下段落。它可能(如文中所示)对大多数实现有效。
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:
Multiple threads can safely read the same container object. (There are nunprotected mutable subobjects within a container object.)
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.)
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.
对于标准 C++ 库中定义的容器对象,例如 STL 容器和模板类 basic_string 的对象,此实现遵循为 SGI STL 阐明的广泛采用的实践:
多个线程可以安全地读取同一个容器对象。(容器对象中有不受保护的可变子对象。)
两个线程可以安全地操作相同类型的不同容器对象。(容器类型中没有不受保护的共享静态对象。)
如果至少有一个线程正在修改对象,则必须防止同时访问容器对象。(明显的同步原语,例如 Dinkum 线程库中的那些,不会被容器对象颠覆。)
因此,没有尝试确保容器对象上的原子操作是线程安全的;但是在适当的粒度级别上创建线程安全的共享容器对象很容易。
回答by Konrad Rudolph
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! §23.1.2.8 states that inserting doesn't invalidate iterators.
哦!§23.1.2.8 指出插入不会使迭代器失效。
回答by user1988707
Performing an insertion can cause the vector to reallocate its underlying memory while iterator may still point to the previous (but invalid) memory address, leading to segment fault.
执行插入会导致向量重新分配其底层内存,而迭代器可能仍指向前一个(但无效)的内存地址,从而导致段错误。
回答by Michael Kohne
Simple explanation: If thread A is moving iterators through the container, it's looking at container internals. 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. This causes crashes in thread A.
简单解释:如果线程 A 在容器中移动迭代器,它正在查看容器内部。如果线程 B 修改了容器(即使是一个不会使 A 拥有的迭代器失效的操作),线程 A 可能会遇到麻烦,因为 B 正在欺骗容器内部,可能使它们处于(暂时)无效状态。这会导致线程 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.
就那么简单。
回答by Brian Neal
Yes. One way to handle this situation is to have each thread lock a shared mutex before accessing the same set object. Make sure you use RAII techniques to lock and unlock the mutex.
是的。处理这种情况的一种方法是让每个线程在访问同一个 set 对象之前锁定一个共享互斥锁。确保您使用 RAII 技术来锁定和解锁互斥锁。