在插入时同时迭代一个映射,这在什么方面是不安全的
Concurrently iterating through a map while inserting, in what way is it unsafe
注意:我知道这是不安全的,并且是标准未定义的,我想看看它是由我的编译器定义的,还是在实践中是安全的。
我在一个线程中迭代映射范围,同时可能在另一个线程插入
// thread 1:
for(auto it = map.begin(); it != map.end(); ++it){
// it's okay if "it" is out of order, repeats an element, or skips an element
// it's bad if "it" can skip map.end() or turn to mush (invalid iterator)
}
// thread 2:
map[Key(...)] = Type(...); // insertions are extremely rare but inevitable
这是不安全的,但是嗯…有多不安全?这个映射作为一个优化提示来缓解线程争用,因此它本身不会对争用做出贡献。如果可能的结果只是插入的元素可能会被遗漏,或者它会无序读取元素或读取两次,那么这是可以接受的,不会破坏任何内容。
这样做会使迭代器变成汤还是会导致map.end()
丢失?这是仅有的两个可能毁掉我生活的结果。
是的,这些结果绝对可能发生,甚至更糟。
在地图中插入时,会发生各种内部操作。这不仅仅是[]
和=
:下面还有一个完整的算法,可能包括重新平衡操作!(有关更多信息,请参阅你以前的大学关于树结构管理的笔记。)
无法保证在这种算法的过程中"观察"地图会产生什么结果,而且标准非常明确地表明,您的程序将具有未定义的行为。这是一个双重问题:你不仅会遇到映射的实际问题,而且你的编译器知道没有定义良好的程序可以进入这种情况,可以根据你没有的假设进行优化。现在,所有的地狱都松了,可能出现在与地图访问无关的代码中。
在一个线程中修改地图,在另一个线程读取地图,而不同步,这是自杀,简单明了。不要试图智胜编译器/实现:只需要契约代码即可。
我在这里半开玩笑,但假设底层集合是通过预先分配固定大小来实现的,然后当需要增长时,它可能会多分配50%,以避免重复的小规模重新分配。然后,旧集合条目将被移动到新分配的内存中,并且旧集合将被解除分配。
如果在插入时迭代这样的集合,"下一个"迭代器可能最终会持有一个指向释放位置的指针。
相关文章:
- 在什么情况下,两个堆栈分配的结构对象的 this 点指向同一个地址?
- 在什么情况下,我想在 C/C++ 代码中使用内联汇编代码
- 在什么条件下使用 std::memcpy 在对象之间复制是安全的?
- 为什么我的代码在指针方面停止运行?
- 在什么情况下,需要共享智能指针而无法使用唯一指针?
- 您应该在什么时候创建自己的异常类型
- 为什么或在什么情况下,你会将参数作为C++中的引用(或指针)传递给函数?
- "using namespace"子句在什么范围内有效?
- printf() 和 std::cout 在指针方面的区别
- 为什么python在循环方面胜过c++
- 在设计方面:重载vector类型的类成员的插入运算符
- 可以在什么上下文中使用指针重排?
- 在什么情况下,使用'const T*'输入参数比'const T&'更可取?
- 如果我提前将参数声明为变量而不是将它们内联写入函数调用,那有什么区别(在内存方面)?
- c++ 类中的静态常量变量和常量变量在存储方面是否有区别
- 在插入时同时迭代一个映射,这在什么方面是不安全的
- Turbo C++7和Dev C++在语法方面有什么区别
- 除了语法,"call by reference"和"call by pointer"在内存方面C++有什么区别吗?
- 在记忆方面"hard-coding"和传递论点有什么区别?
- vector::push_back在内存方面发生了什么?