std::map 访问线程是不是安全,如果它的迭代器永远不会失效

Posted

技术标签:

【中文标题】std::map 访问线程是不是安全,如果它的迭代器永远不会失效【英文标题】:Is std::map access thread safe if iterators to it are never invalidatedstd::map 访问线程是否安全,如果它的迭代器永远不会失效 【发布时间】:2019-03-07 02:18:02 【问题描述】:

所以我想生成这样的地图:std::map<std::string, std::atomic<bool>>。我的用例是一些运行时检查,以查看是否满足某些条件(真或假);我在这张地图中缓存了条件检查的结果,因为这些检查很昂贵。

我的想法是我使用std::call_once 预先填充此地图,然后不再删除或插入元素。但是,我可以通过 find() 并发访问它,这些访问可能会使用 store(true) 更改 std::atomic 值的值。

现在我想知道这是否是线程安全的?我必须承认我觉得我在这里处于未定义的行为领域。

【问题讨论】:

如果您的地图在多个线程开始搜索之前已完全构建,那就没问题了。 请注意,[] 运算符可能会修改地图,因此如果使用它,所有赌注都将被取消。前提是地图从不修改,这是安全的;确保它安全的最好方法是确保如果没有发生编译错误。这可以很容易地确保地图在构建后始终为const。确保它的最佳方法是使其成为const 类成员,并在类的构造函数的初始化部分中完全创建它。这将证明映射始终是 const 的,不能被修改,因此是线程安全的。 @SamVarshavchik 考虑到他们打算修改映射的(原子)值,我认为他们不能让地图为 const。 这可以通过将 map 的值作为一个具有 atomic 标志的类作为可变类成员来解决。 【参考方案1】:

如果对它的迭代器永远不会失效,那么 std::map 访问线程是否安全

这不是充分前提。插入不会使迭代器失效,但会引入与其他访问线程的竞争。

我的想法是我预先填充这张地图

这似乎足够了。只要没有线程修改它,从多个线程并发读取(查找、遍历等)标准映射是安全的。

这些访问可能会改变std::atomic的值

访问,甚至写一个原子对象也是线程安全的。但请记住,多个原子操作序列并不是一个整体。

【讨论】:

以上是关于std::map 访问线程是不是安全,如果它的迭代器永远不会失效的主要内容,如果未能解决你的问题,请参考以下文章

多线程访问一个 std::map 会导致不安全的行为吗?

std::map 上可能的线程不安全操作

std::map 和线程安全的奇怪问题

线程安全的定义

std::unordered_map 上的线程安全包装器

线程安全std :: map:锁定整个地图和各个值[重复]