对 std::vector 元素的赋值是线程安全的吗?
Posted
技术标签:
【中文标题】对 std::vector 元素的赋值是线程安全的吗?【英文标题】:Is assignment to a std::vector element thread-safe? 【发布时间】:2017-05-14 06:05:38 【问题描述】:我创建了一个线程池,它同时写入同一个向量。
这个实现线程安全吗?
如果不是,我应该如何解决?
std::vector<double> global_var;
void func1(int i)
global_var[i]=some_computation(i /* only depends on i */);
void load_distribution()
const int N_max=100;
global_var.assign(N_max,0.0);
std::vector<std::thread> th_pool;
for(long i=0;i<N_max;i++)
th_pool.push_back(std::thread(func1,i));
for(std::thread& tp : th_pool)
tp.join();
更新
在所有线程终止之前,global_var
不会被程序的任何其他部分触及。
【问题讨论】:
虽然我不想承认,但当前的 sn-p 实际上是线程安全的。 ...不过,你的设计真的很脆弱。您的代码的另一部分可能会修改global_var
,这将引入未定义的行为
@WhiZTiM 我保证,在所有线程终止之前,global_var
不会被程序的任何其他部分更改。
完整代码here以防万一。
【参考方案1】:
假设您的 global 向量没有被任何其他代码部分修改,那么您的代码是线程安全的。
每个线程都将写入(访问)向量的不同单元格,因此不存在“脏更新”问题。
此外,向量的类型是双精度型,在现代架构中大于 WORD 型。所以每个数组单元格之间不会相互重叠。
【讨论】:
非常感谢。如果我使用vector<complicatedObj>
会怎样。有什么问题吗?
@ar2015 如果内存以对齐方式分配,则不会
什么是对齐方式的内存分配或什么是非对齐方式的例子?
@ar2015 几个月前我已经回答了这个问题。如果你想看here
正如您所说,如果我使用vector<complicatedObj>
,其中complicatedObj
本身包含多个vector
s,则代码可能会失败。我说的对吗?【参考方案2】:
[container.requirements.dataraces]/1-2:
1 为避免数据争用 ([res.on.data.races]), 实现应将以下函数视为
const
:begin
、end
、rbegin
、rend
、front
、back
、data
、[...]、at
和,除了关联或无序 关联容器,operator[]
。2 尽管有 ([res.on.data.races]),但仍需要实现 当包含对象的内容在 同一个容器中的不同元素,除了
vector<bool>
,是 同时修改。
【讨论】:
【参考方案3】:一般来说,std::vector
不是线程安全的,但上面的代码可以工作,因为支持数组是使用assign()
方法预先分配的。
只要编写者不重新分配后备数组,代码就可以工作。 assign()
方法会预先分配足够的空间,因此线程写入时不会发生这种情况。
【讨论】:
其实一个assignment已经用过了global_var.assign(N_max,0.0);
如果我使用 vector<object>
代替 vector<double>
会怎样,它内部将包含其他向量。在这种情况下,赋值会使向量无效吗?
@ar2015 :不,它不会修改外部向量,它只会触及每个元素的内容。并且由于外部支持数组不会被修改,特定元素的修改将是线程安全的。当然,只要只有一根线接触它们。以上是关于对 std::vector 元素的赋值是线程安全的吗?的主要内容,如果未能解决你的问题,请参考以下文章
std :: vector是否将其值类型的赋值运算符用于push_back元素?