【发布时间】:2011-08-20 05:32:37
【问题描述】:
stl map 线程上的 find 调用安全吗?
【问题讨论】:
-
线程安全相对于什么?是否所有线程都只调用
find()或其他const方法?地图是否正在被另一个线程更新? -
假设所有线程都只调用
find()。线程安全吗?
标签: c++ multithreading stl map thread-safety
stl map 线程上的 find 调用安全吗?
【问题讨论】:
find() 或其他const 方法?地图是否正在被另一个线程更新?
find()。线程安全吗?
标签: c++ multithreading stl map thread-safety
不,C++ 规范在规范中不保证任何 STL 容器上的操作的线程安全。如果线程安全很重要,您应该提供自己的锁定。
话虽如此,不同的实现似乎提供了不同的保证。例如,大多数似乎允许多个并发读取器,只要没有同时执行写入。如果您不关心可移植性,则可以研究实现文档。例如来自here 的 SGI STL:
STL 的 SGI 实现是 线程安全仅在某种意义上 同时访问不同的 容器是安全的,同时 对共享容器的读取访问 是安全的。如果多个线程访问一个 单个容器,以及至少一个 线程可能会写,那么 用户有责任确保 线程之间的互斥 在容器访问期间。
来自this answer,Dinkumware 似乎也做出了类似的保证(他们让微软的 STL 实现)。
多个线程可以安全地读取 相同的容器对象。 (有 nunprotected 内的可变子对象 一个容器对象。)
两个线程可以安全地操作 不同的容器对象 同类型。 (没有不受保护的 共享静态对象 容器类型。)
您必须防止同时发生 访问容器对象,如果在 至少有一个线程正在修改 目的。 (明显的同步 原语,例如那些在 Dinkum 线程库,不会 被容器对象颠覆。)
【讨论】:
std::map<>::find()。
否:当另一个线程与您的 find 同时更新地图时,行为未定义。
【讨论】:
我试图找到问题的答案。
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 }
【讨论】:
实际上,Microsoft Visual Studio 2008 附带的 STL 似乎对修改地图的操作有一些锁定(我假设它与 set 相同)。这很烦人,因为我要在多个线程中构建更多地图,这会影响我的性能。
【讨论】: