我读过on Stackoverflow, none of the STL containers are thread-safe for writing . 但这在实践中意味着什么?这是否意味着我应该将可写数据存储在普通数组中?
我期望对 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);
}
第一个实现是否真的比第二个更好a)在线程安全方面和b)在性能方面?我更喜欢使用std :: vector,因为我对C风格的数组不太熟悉 .
编辑:我删除了 #pragma omp atomic update
保护写 .
4 回答
这两个人同样安全 . 如果没有从多个线程访问任何元素就可以了 . 您的并行循环将只访问每个元素一次,因此只能访问一个线程 .
标准中有空间,容器的成员函数是非线程安全的 . 在这种情况下,您使用
vector<int>::operator[]
,因此您'd want an explicit guarantee of thread-safety for that member, which seems reasonable since calling it even on a non-const vector doesn' t修改向量本身 . 所以我怀疑's a problem in this case, but I haven' t寻找保证[编辑:rici找到它] . 即使它可能不安全,你可以在循环之前做int *dataptr = &data.front()
然后索引dataptr
而不是data
.顺便说一句,这个代码不能保证
vector<bool>
的安全,因为它是一个特殊情况,多个元素在一个对象中共存 . 对于bool
数组来说是安全的,因为它的不同元素是不同的"memory locations"(C11中为1.7) .对于指定数据争用规则的c 11,描述了容器的线程安全性 . 该标准的相关部分是§23.2.2,第2段:
除非特别允许,否则上面提到的§17.6.5.9基本上禁止任何标准库接口的任何并发修改,因此我引用的部分确切地告诉您允许的内容(包括您的使用) .
由于Steve Jessop提出了这个问题,§23.2.2的第1段明确允许在序列容器中同时使用
[]
:它的主要意思是,如果你有多个线程访问向量,你不能依赖C来防止多个并发写入破坏数据结构 . 所以你需要使用某种防守 . 另一方面,如果你的程序没有使用多个线程,就像你的例子似乎没有,你就完全没问题了 .
在这种情况下,您应该只使用必要数量的值构建向量?一切都会好起来的 .
resize()
效果很好 . 表现将是平等的 . 多线程访问不会破坏向量的原因是:您的数据位于其位置,不会从那里移动 . OMP线程一次不会访问同一个元素 .