【问题标题】:Read safety of std::map / std::unordered_map读取 std::map / std::unordered_map 的安全性
【发布时间】:2023-03-30 02:42:01
【问题描述】:

我有一个我读写的 std::map(或 std::unordered_map,因为我认为它们的行为相似)。我也有一个关联的互斥体。

我将同时读取和写入(通过插入或删除元素)到地图。我听说 STL 容器是读安全的。如果是这样,只使用互斥体进行写操作是否安全?

我之所以这样问,是因为我需要在某一时刻迭代映射的值,并且我只想在元素需要修改时使用我的互斥锁。

【问题讨论】:

    标签: c++11 concurrency thread-safety stdmap


    【解决方案1】:

    仅将互斥锁用于写操作是否安全?

    您需要确保在写入地图时不要尝试读取地图。因此,您不需要在仅发生读取时锁定互斥锁,但如果任何线程可以写入,那么所有线程(甚至读取器)都需要使用互斥锁。

    【讨论】:

      【解决方案2】:

      一般来说,不会。读取器和写入器都必须获取互斥锁。

      否则,当存在并发读取和写入时,您将面临数据竞争的风险,从而导致未定义的行为。在实践中,可能会导致崩溃,或者读者可能会获得您从未放入地图的损坏数据。即使它看起来有效,它也会混淆诸如种族检测器之类的有用工具(例如,thread sanitizerHelgrind)。它还使您的代码可能无法移植。

      只有当你可以证明没有更多的写入者,并且所有其他线程都可以看到更改时,情况才会改变,因为现在所有访问都是读取者。此时,不会发生任何数据竞争,无需任何同步即可安全地从地图中读取。

      如果仍有更新的可能,您可以使用并行数据结构来避免锁定。 C++11(和 C++17)不提供,但有非标准实现可用。

      所以,如果你真的需要性能,你可以看看这些并发哈希映射实现(否则只需将std::unordered_map 与所有访问的互斥体结合使用):

      • Concurrent data structures 在英特尔线程构建模块 (TBB)
      • Junction(似乎是最快的,但需要线程在不使用映射时定期调用清理操作。这样做是为了回收内存而不必使用垃圾收集器,如“安全内存回收”中所述在介绍blog post。)

      【讨论】:

        猜你喜欢
        • 2017-11-15
        • 2022-01-13
        • 2012-03-08
        • 2013-02-10
        • 1970-01-01
        • 2021-05-30
        • 2010-12-23
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多