【发布时间】:2020-04-09 18:00:44
【问题描述】:
我有一个嵌套循环,外部迭代很少,内部迭代很多。在内部循环中,我需要计算一个总和,所以我想使用 OpenMP 缩减。外部循环位于容器上,因此减少应该发生在该容器的元素上。 这是一个最小的人为示例:
#include <omp.h>
#include <vector>
#include <iostream>
int main(){
constexpr int n { 128 };
std::vector<int> vec (4, 0);
for (unsigned int i {0}; i<vec.size(); ++i){
/* this does not work */
//#pragma omp parallel for reduction (+:vec[i])
//for (int j=0; j<n; ++j)
// vec[i] +=j;
/* this works */
int* val { &vec[0] };
#pragma omp parallel for reduction (+:val[i])
for (int j=0; j<n; ++j)
val[i] +=j;
/* this is allowed, but looks very wrong. Produces wrong results
* for std::vector, but on an Eigen type, it worked. */
#pragma omp parallel for reduction (+:val[i])
for (int j=0; j<n; ++j)
vec[i] +=j;
}
for (unsigned int i=0; i<vec.size(); ++i) std::cout << vec[i] << " ";
std::cout << "\n";
return 0;
}
问题是,如果我将缩减子句写为(+:vec[i]),我会收到错误‘vec’ does not have pointer or array type,它的描述性足以找到解决方法。但是,这意味着我必须引入一个新变量并在一定程度上更改代码逻辑,而且我发现看代码应该做什么不太明显。
我的主要问题是,是否有更好/更清洁/更标准的方法来编写容器元素的缩减。
我也想知道上面代码中显示的第三种方式有点为什么以及如何工作。我实际上正在使用Eigen 库,该变体在其容器上似乎工作得很好(虽然还没有进行广泛的测试),但在std::vector 上,它产生的结果介于零和实际结果之间(8128 )。我认为它应该可以工作,因为vec[i] 和val[i] 应该 都评估为取消引用相同的地址。但很可惜,显然不是。
我正在使用 OpenMP 4.5 和 gcc 9.3.0。
【问题讨论】: