【问题标题】:Is std::vector thread-safe and concurrent by default? Why or why not?std::vector 默认是线程安全和并发的吗?为什么或者为什么不?
【发布时间】:2025-08-05 03:40:02
【问题描述】:

使动态数组线程安全和并发是什么意思? 例如,std::vector

  1. 可能需要在同一位置插入两个线程。无需同步,因为它将根据线程调度完成。
  2. 一个线程擦除而另一个线程访问相同的元素?我认为这不是数据结构问题,而是使用问题。

那么有什么需要在std::vector 上完成以使其成为线程安全和并发的,还是默认情况下是线程安全和并发的?

【问题讨论】:

  • 除非明确说明,否则请考虑 everything 线程不安全,这样您的假设就会在安全方面出错。而且您的两个示例都需要某种同步或互斥,请记住,线程可以随时被抢占。
  • 唯一可以在标准容器(std::vector 是其中之一)上可靠地同时执行的操作是 read。一旦您在 中为同一对象引入并发写操作的潜在,*就会开始脱落,除非对象本身支持这种情况下的原子更新,否则*就会离开车辆.如果容器本身要经历任何可能会改变布局的机制,那么车轮已经在你身后四分之一英里处。
  • STL 容器在您的场景中不是线程安全的。您必须使用锁来序列化访问,或者使用线程安全的不同容器
  • @PanagiotisKanavos:链接 boost.org 时,将 URL 中的版本号替换为“release”。这样您的链接就不会过时。

标签: c++ vector data-structures concurrency lock-free


【解决方案1】:

C++11 对标准库中容器的线程安全有如下说法:

23.2.2 容器数据竞争 [container.requirements.dataraces]

为了避免数据竞争 (17.6.5.9),实现应 将以下函数视为 const:beginendrbegin, rend, front, back, data, find, lower_bound, upper_boundequal_rangeat 和,除了关联或 无序关联容器,operator[].

尽管有 (17.6.5.9),但仍需要实现以避免数据 当包含的对象的内容在不同的元素中时竞争 以相同的顺序,除了vector<bool>,被修改 同时。

所以,基本上从多个线程从容器中读取是可以的,修改容器中已经存在的元素也可以(只要它们是不同的元素)。

因此,对于std::vector,您的两个更具体的问题都不是线程安全的:

1) 插入向量的两个线程正在修改向量本身 - 不是现有的单独元素。

2) 一个线程擦除和其他线程访问同一元素是不安全的,因为从向量中擦除一个元素并不是一个承诺线程安全的操作(或“无数据竞争”,作为标准放)。

要安全地执行这些操作,程序本身需要进行一些外部同步。

【讨论】:

  • 清除为泥迈克尔:p.
  • 我认为重要的部分是隐含的:添加或删除不是线程安全的。这个答案应该被修改为除了描述的那些之外的任何其他操作是nottrhead-safe
  • 虽然列出的操作可能是线程安全的,但它们不是并发的。例如,当一个线程在向量上使用下标运算符[] 来获取索引 X 处的元素时,线程在调用开始时中断,另一个线程在索引之前插入一个新元素X。那么初始线程仍将获取索引 X 处的元素,但它可能不是线程预期的数据。
  • @JoachimPileborg:插入操作不是被列为“数据竞争安全”的操作。所以 23.2.2 并不建议您描述的情况是安全的。
  • 允许同时修改同一元素如果元素单独为atomic。但请注意,atomic<T> 没有复制构造函数,因此不可能使用任何函数来检查它们是否必须增长向量,无论您采取何种步骤来确保它不需要需要增长.在 C++ 中,仍然需要编译从未采用的分支中的代码。 How to declare a vector of atomic in C++)。这仍然不能安全地修改容器本身,只能修改其中的元素。
【解决方案2】:

标准库中唯一安全的单个对象的并发操作是 - 只访问const-member 函数 - 对同步原语的所有访问(如互斥锁和解锁或原子操作) 其他一切都必须在外部同步。特别是标准库还没有任何线程安全的容器(c++14)

因此,您对这两个示例的回答是否定的,它们都需要某种形式的外部同步。

你当然可以做的是修改容器中两个不同元素的值。

【讨论】: