stl vector并发读取线程安全吗?

时间:2011-09-17 15:50:53

标签: c++ concurrency stl thread-safety language-lawyer

我正在开发一个应用程序,其中大量的线程需要迭代一组字符串值,并尝试将它自己的数据与列表中可用的数据相匹配。

我正在寻找以下用例:

  1. 使用std :: string类型的少数元素初始化Vector。 (可以说对象名是strList)。 strList将在应用程序启动时初始化。
  2. 所有线程都将遍历strList以查看它的值是否与strList的至少一个元素匹配。
  3. 没有线程会尝试修改strList,它将严格用作只读对象。
  4. 那么请告诉我并发读取是否对矢量对象是线程安全的。我使用的是RHEL 6,gcc版本是4.5.x

3 个答案:

答案 0 :(得分:37)

对于您提到的场景,

,它完全是线程安全的。


实际上,STL并不是一种正确的引用方式 这是 C++ Standard Library

C ++ 03标准根本不讨论并发性,因此并发性方面被省略为编译器的实现细节。因此,编译器附带的文档是应该查找与并发相关的答案的地方。

大多数STL实现都是线程安全 但是对于来自多个线程的同一对象的并发读取,大多数STL实现确实是线程安全的。

<强>参考文献:

MSDN 说:

  

单个对象是从多个线程读取的线程安全的。例如,给定一个对象A,可以安全地从线程1和线程2同时读取A.

Dinkumware STL-Documentation 说:

  

多个线程可以安全地读取同一个容器对象。 (容器对象中有nunprotected mutable子对象。)

GCC Documentation 说:

我们目前使用线程安全的 SGI STL 定义,其中声明:

  

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

从上面可以看出,是的,GCC中的线程安全是从多个线程同时读取同一个对象。

注意:GCC的标准库是SGI的STL代码的衍生物。

答案 1 :(得分:9)

在C ++ 0x FDIS(n3290)中有针对性的提及。

  

§17.6.5.9避免数据竞争

整段是有意义的,但更具体的是:

  

3 / C ++标准库函数不应直接或间接修改除当前线程以外的线程可访问的对象(1.10),除非通过函数的非const参数直接或间接访问对象包括这个。

表示您可以安全地致电cbegin上的cendstd::vector<T>。与在operator==上调用operator<std::string一样。

  

6 / 通过调用标准库容器或字符串成员函数获得的迭代器上的操作可以访问底层容器,但不得修改它。

意味着仅仅迭代容器不应该以任何方式修改所述容器。

尽管 3 / ,但是,似乎有全局对象的空间,因为迭代器修改某种共享寄存器对象,在这些对象中它们将自己与容器相关联(STL调试功能)。我没理解:

  

7 / 如果对象对用户不可见并且受到数据竞争保护,则实现可以在线程之间共享自己的内部对象。

否则。

无论如何,标准保证迭代vector将是安全的......但是在实际读取对象(这些是你自己的)时不能保证。在这种情况下,我们会介绍这一点,因为std::string已在上面介绍。

编辑:正如David Hammen所说,该标准尚未完全实施。许多编译器已经提供了上述保证,即使之前的标准从未提及线程。 MSVC,gcc,clang,icc,comeau等......从Als的回答中可以看出,所有大牌都应该已经提供了这种保证。

答案 2 :(得分:2)

除了关于数据竞争规避的一般规则外,在[container.requirements.dataraces]中标准说

  

-1-为了避免数据争用(17.6.5.9),实现应考虑以下函数为constbeginendrbeginrendfrontbackdatafindlower_boundupper_boundequal_range,{{ 1}}和除关联或无序关联容器外,at

所以,即使你打电话给非常数operator[] / begin()等,只要你不实际修改它是安全的。