cls*_*udt 19 c++ stl openmp thread-safety
我已经在Stackoverflow上读到,没有一个STL容器对于写入是线程安全的.但这在实践中意味着什么?这是否意味着我应该将可写数据存储在普通数组中?
我希望并发调用std::vector::push_back(element)可能会导致数据结构不一致,因为它可能需要调整向量的大小.但是这样的情况呢,不涉及调整大小:
1)使用数组:
int data[n];
// initialize values here...
#pragma omp parallel for
for (int i = 0; i < n; ++i) {
data[i] += func(i);
}
Run Code Online (Sandbox Code Playgroud)
2)使用`std :: vector``:
std::vector<int> data;
data.resize(n);
// initialize values here...
#pragma omp parallel for
for (int i = 0; i < n; ++i) {
data[i] += func(i);
}
Run Code Online (Sandbox Code Playgroud)
第一个实现是否真的比第二个更好a)在线程安全方面和b)在性能方面?我更喜欢使用std :: vector,因为我对C风格的数组不太熟悉.
编辑:我删除了#pragma omp atomic update保护写.
Ste*_*sop 24
这两个人同样安全.如果没有从多个线程访问任何元素就可以了.您的并行循环将只访问每个元素一次,因此只能访问一个线程.
标准中有空间,容器的成员函数是非线程安全的.在这种情况下你使用vector<int>::operator[],所以你想要明确保证该成员的线程安全性,这似乎是合理的,因为即使在非const向量上调用它也不会修改向量本身.所以我怀疑在这种情况下存在问题,但我没有寻找保证[编辑:rici发现它].即使它可能不安全,你可以int *dataptr = &data.front()在循环之前做,然后索引dataptr而不是data.
另外,这个代码不能保证安全vector<bool>,因为它是一个特殊情况,多个元素在一个对象中共存.对于一个数组来说是安全的bool,因为它的不同元素是不同的"存储位置"(C++ 11中的1.7).
ric*_*ici 18
对于指定数据争用规则的c ++ 11,描述了容器的线程安全性.该标准的相关部分是§23.2.2,第2段:
尽管如此(17.6.5.9),除了vector <bool>之外,同时修改同一序列中不同元素中包含对象的内容时,还需要实现以避免数据争用.
[注意:对于大小大于1的向量<int> x,x [1] = 5和*x.begin()= 10可以在没有数据争用的情况下同时执行,但是x [0] = 5和*并发执行的x.begin()= 10可能导致数据竞争.作为一般规则的例外,对于向量<bool> y,y [0] = true可以与y [1] = true竞争. - 尾注]
除非特别允许,否则上面提到的§17.6.5.9基本上禁止任何标准库接口的任何并发修改,因此我引用的部分确切地告诉您允许的内容(包括您的使用).
由于Steve Jessop提出了这个问题,第23.2.2段第1段明确允许同时使用[]顺序容器:
为避免数据争用(17.6.5.9),实现应将以下函数视为const:begin,end,rbegin,rend,front,back,data,find,lower_bound,upper_bound,equal_range,at和,除了关联或无序的关联容器,operator [].