写一个std :: vector vs plain数组的安全性
我读过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);
}
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);
}
在线程安全性和b)性能方面,第一个实现是否比第二个实现更好? 我宁愿使用std :: vector,因为我对C风格的数组不太舒服。
编辑:我删除了保护写的#pragma omp atomic update
。
这两者同样安全。 如果没有元素可以从多个线程访问,那你可以。 你的并行循环只会访问每个元素一次,因此只能从一个线程访问。
标准中容器的成员函数有一个空间是非线程安全的。 在这种情况下,你使用vector<int>::operator[]
,所以你希望明确保证该成员的线程安全,因为即使在非const矢量上调用它也不会修改向量本身。 所以我怀疑在这种情况下存在问题,但我没有寻找保证[编辑:rici找到它]。 即使它可能不安全,您可以在循环前执行int *dataptr = &data.front()
,然后索引data
dataptr
而不是data
。
vector<bool>
说一句,这个代码不能保证vector<bool>
安全,因为它是一个特殊情况,多个元素在一个对象内共存。 对于一个bool
数组来说是安全的,因为它的不同元素是不同的“内存位置”(1.7在C ++ 11中)。
对于指定数据竞争规则的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),实现应将以下函数视为常量:在关联中除了关联外,开始,结束,rbegin,rend,front,back,data,find,lower_bound,upper_bound,equal_range或者无序的关联容器operator []。
它的主要意思是,如果你有多个线程访问矢量,你不能依靠C ++来防止用多个并发写入破坏数据结构。 所以你需要使用某种警卫。 另一方面,如果你的程序没有使用多个线程,就像你的例子似乎没有,你完全没问题。
链接地址: http://www.djcxy.com/p/76139.html