仍然是矢量并发读线程安全的

Is stl vector concurrent read thread-safe?

本文关键字:线程 安全 并发 仍然是      更新时间:2023-10-16

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

我正在寻找以下用例:

  1. Vector用std::string类型的几个元素初始化。(假设对象名为strList)。strList将在应用程序启动时初始化。
  2. 所有线程都将遍历strList,看看它的值是否至少与strList中的一个元素匹配。没有线程会试图修改strList,它将被严格地用作只读对象。

所以你能告诉我并发读在向量对象上是线程安全的吗?我使用RHEL 6和gcc版本是4.5。x

对于您提到的场景,它是完美的线程安全。


实际上,STL并不是一种正确的引用方式。
c++标准库

c++ 03标准根本没有讨论并发性,因此并发性方面被遗漏为编译器的实现细节。因此,编译器附带的文档是您应该寻找与并发相关的答案的地方。

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

引用:

MSDN说:

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

Dinkumware STL-Documentation说:

多线程可以安全地读取同一个容器对象。(容器对象中存在不受保护的可变子对象)

GCC Documentation说:

我们目前使用的是SGI STL对线程安全的定义,它声明:

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

所以从上面来看,是的,在GCC中从多个线程并发读取同一个对象是线程安全的。

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

在c++ 0x FDIS (n3290)中对此有特别提到。

§17.6.5.9数据避免种族

整段都很有趣,但更特别的是:

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

表示在std::vector<T>上可以安全地调用cbegincend。以及在std::string上调用operator==operator<

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

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

尽管3/,但似乎还是有全局对象的空间,因为迭代器修改了某种共享寄存器对象,它们将自己与容器关联在一起(STL调试特性)。我不明白:

7/实现可以在线程之间共享自己的内部对象,如果这些对象对用户不可见,并且可以防止数据争用。

无论如何,标准保证在vector上迭代是安全的…但是当涉及到实际读取对象(这些是您自己的)时,不保证。在本例中,因为上面已经讨论了std::string,所以没有讨论这个问题。

EDIT:正如David Hammen公正地指出的,本标准尚未完全实现。许多编译器已经提供了上述保证,尽管以前的标准从未提到线程。MSVC, gcc, clang, icc, comau等…从Als的回答中可以看出,所有的大牌应该已经提供了这样的保证。

除了关于避免数据竞争的通用规则外,在[container.requirements.]标准说

-1-为了避免数据争用(17.6.5.9),实现应将以下函数视为const: begin, end, rbegin, rend, front, back, data, find, lower_bound, upper_bound, equal_range, at以及operator[](除了在关联或无序关联容器中)。

所以即使你调用非const begin()/end()等,只要你不修改任何东西,它是安全的。