【问题标题】:stl map find thread safestl map 找到线程安全
【发布时间】:2011-08-20 05:32:37
【问题描述】:

stl map 线程上的 find 调用安全吗?

【问题讨论】:

  • 线程安全相对于什么?是否所有线程都只调用find() 或其他const 方法?地图是否正在被另一个线程更新?
  • 假设所有线程都只调用find()。线程安全吗?

标签: c++ multithreading stl map thread-safety


【解决方案1】:

不,C++ 规范在规范中不保证任何 STL 容器上的操作的线程安全。如果线程安全很重要,您应该提供自己的锁定。

话虽如此,不同的实现似乎提供了不同的保证。例如,大多数似乎允许多个并发读取器,只要没有同时执行写入。如果您不关心可移植性,则可以研究实现文档。例如来自here 的 SGI STL:

STL 的 SGI 实现是 线程安全仅在某种意义上 同时访问不同的 容器是安全的,同时 对共享容器的读取访问 是安全的。如果多个线程访问一个 单个容器,以及至少一个 线程可能会写,那么 用户有责任确保 线程之间的互斥 在容器访问期间。

来自this answer,Dinkumware 似乎也做出了类似的保证(他们让微软的 STL 实现)。

多个线程可以安全地读取 相同的容器对象。 (有 nunprotected 内的可变子对象 一个容器对象。)

两个线程可以安全地操作 不同的容器对象 同类型。 (没有不受保护的 共享静态对象 容器类型。)

您必须防止同时发生 访问容器对象,如果在 至少有一个线程正在修改 目的。 (明显的同步 原语,例如那些在 Dinkum 线程库,不会 被容器对象颠覆。)

【讨论】:

  • 但是,大多数实现都提供了一些保证,例如多个同时 readers 不需要锁定。因此,多个线程可以安全地使用std::map<>::find()。
  • @Andre,这似乎是大多数实现所提供的
  • 我发誓我今天遇到了线程安全问题,当时多个线程(在 openMP 并行 for 循环中 - VisualStudio 2010)是 /reading/ 一个 STL 容器:我的线程正在执行 std::map。 find() 在相​​同的数据上并行。在调试模式下,它甚至似乎死锁了,而在发布时,它会给我的应用程序带来问题,而这些问题在删除并行 for 循环时不会出现。
【解决方案2】:

否:当另一个线程与您的 find 同时更新地图时,行为未定义。

【讨论】:

    【解决方案3】:

    我试图找到问题的答案。

    https://gcc.gnu.org/onlinedocs/libstdc++/libstdc++-html-USERS-3.4/stl__map_8h-source.html

    你可以看到stl map souce。


    搜索find()。在497行、524行找到。代码写成_M_t.find(__x);


    然后搜索_M_t。

    在第 124 行找到。 写成_Rep_type _M_t;


    如果属性_M_t 是为每个线程创建的,它可能是线程安全的。 但我不这么认为。 如果 2 个线程同时使用 find,它们将同时使用 _M_t。 _Rep_type 连接到 _Rb_tree。

    您可以在下面的源代码中看到_Rb_tree。

    https://gcc.gnu.org/onlinedocs/libstdc++/libstdc++-html-USERS-4.1/stl__tree_8h-source.html

    find() 做树旅行(见下面的代码)。 __x 和 __y 会发生非自愿更改。

    01307   template<typename _Key, typename _Val, typename _KeyOfValue,
    01308            typename _Compare, typename _Alloc>
    01309     typename _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::iterator
    01310     _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::
    01311     find(const _Key& __k)
    01312     {
    01313       _Link_type __x = _M_begin(); // Current node.
    01314       _Link_type __y = _M_end(); // Last node which is not less than __k.
    01315 
    01316       while (__x != 0)
    01317     if (!_M_impl._M_key_compare(_S_key(__x), __k))
    01318       __y = __x, __x = _S_left(__x);
    01319     else
    01320       __x = _S_right(__x);
    01321 
    01322       iterator __j = iterator(__y);
    01323       return (__j == end()
    01324           || _M_impl._M_key_compare(__k,
    01325                     _S_key(__j._M_node))) ? end() : __j;
    01326     }
    

    【讨论】:

      【解决方案4】:

      实际上,Microsoft Visual Studio 2008 附带的 STL 似乎对修改地图的操作有一些锁定(我假设它与 set 相同)。这很烦人,因为我要在多个线程中构建更多地图,这会影响我的性能。

      【讨论】:

        猜你喜欢
        • 2017-08-27
        • 1970-01-01
        • 1970-01-01
        • 2013-02-10
        • 1970-01-01
        • 2022-01-22
        • 2012-10-07
        • 1970-01-01
        相关资源
        最近更新 更多