问题 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