Visual C++2010中STL映射的实现与线程安全

STL map implementation in Visual C++ 2010 and thread safety

本文关键字:实现 线程 安全 映射 C++2010 STL Visual      更新时间:2023-10-16

我知道,只要不需要调整大小,就可以读取一些单元格并同时写入STL向量的不同单元格。我想知道,如果我保证每个线程访问/插入一个不同的键,是否允许在Visual C++2010中同时获取一些键的值,并同时向STL映射插入新的键值对。

发件人http://www.cplusplus.com/reference/map/map/operator[]/:

数据竞赛:

容器被访问,并且可能被修改。函数访问元素并返回可用于修改的引用其映射值。同时访问其他元素是安全的。如果该函数插入一个新元素,同时迭代中的范围这个集装箱不安全。

这意味着,如果我插入一个新元素,我就不能在容器上迭代。问题是访问不同的元素是否需要在容器上迭代。那安全吗?

如果我保证集装箱的尺寸永远不会超过N,这会安全吗?然后,也许映射的内部数据结构可以被预先分配,并且只要向量没有调整大小,就可以像向量的内部一样保持不变。

我知道有可用的map的线程安全实现,但它们可能要慢得多,所以我想知道标准map在我的情况下是否足够,因为我正在修改的代码是我应用程序中的热点。

谢谢,Michal

我想知道,如果我保证每个线程访问/插入一个不同的键,是否允许在Visual C++2010中同时获取一些键的值,并同时向STL映射插入新的键值对。

不,这是不允许的。查找涉及内部数据结构的遍历(对于std::map,内部表示的常见方法是像红-黑树一样的二进制搜索树)。另一方面,插入修改内部结构。

如果同时查找和插入是线程安全的,那么每次访问,即使是在单线程环境中,也会涉及到高昂的操作同步成本,这与C++原则相矛盾——"你会为你不使用的东西付费"。

MSVC 2010中的线程安全:

如果一个线程正在写入单个对象,那么在同一个或其他线程上对该对象的所有读取和写入都必须受到保护。例如,给定一个对象A,如果线程1正在向A写入,则必须阻止线程2从A读取或向A写入。

也就是说,如果在其他线程中插入操作之前已经有了对元素的引用,那么通过该引用访问元素是安全的,因为在内部重新平衡期间不会移动对象。

ISO C++11 23.2.4/9:

插入和模板成员不应影响迭代器和对容器的引用的有效性,擦除成员应仅使迭代器或对已擦除元素的引用无效。


MSVC 2012(但不是MSVC 2010)有concurrency::concurrent_unordered_map关联容器(注意,它是无序,这使它类似于std::unordered_map,即它需要密钥的散列和相等性,而不是严格的弱排序):

concurrent_unordered_map类是一个并发安全容器,用于控制类型为s的td::pair<const _Key_type, _Element_type>的可变长度元素序列。序列的表示方式支持并发安全附加、元素访问、迭代器访问和迭代器遍历操作。


英特尔TBB库有类似的容器-tbb::concurrent_unordered_map:

支持并发插入和遍历的关联容器的模板类。