问题 stl map查找线程安全


在stl map线程上找到调用是否安全?


9614
2018-05-06 14:01


起源

也可以看看: stackoverflow.com/questions/1362110/... - Doug T.
关于什么线程安全?是否所有线程都只是调用 find()或其他 const 方法?地图是否被另一个线程更新? - André Caron
让我们假设所有线程都只是在调用 find()。线程安全? - huseyin tugrul buyukisik


答案:


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

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

STL的SGI实现是   线程安全只在某种意义上说   同时访问不同的   容器是安全的,同时的   读取对共享容器的访问   很安全。如果多个线程访问a   单个容器,至少一个   线程可能会写,然后   用户负责确保   线程之间相互排斥   在容器访问期间。

从 这个答案,Dinkumware似乎也做出了类似的保证(他们制作了微软的STL实现)。

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

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

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


11
2018-05-06 14:03



但是,大多数实现提供了一些保证,例如多个同时保证 读者 不需要锁定。因此,可以使用多个线程 std::map<>::find() 安全。 - André Caron
@Andre,这似乎是大多数实现提供的 - Doug T.
我发誓我今天遇到了一个线程安全问题,当多个线程(在一个openMP并行for循环 - VisualStudio 2010)中/读取/一个STL容器时:我的线程在同一个线程上并行执行std :: map.find()数据。在调试模式下,它甚至似乎死锁,并且在发布时,它会导致我的应用程序在删除并行for循环时不会出现问题。 - WhitAngl


我试图找到问题的答案。

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     }

3
2017-08-04 08:13





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


2
2018-05-06 14:03





实际上,Microsoft Visual Studio 2008附带的STL似乎对修改映射的操作有一些锁定(我认为它与set相同)。这是相当烦人的,因为我正在多个线程中构建更多的地图,这正在扼杀我的表现。


0
2018-05-08 15:44