初始化变量以进行 omp 缩减
Initialize variable for omp reduction
OpenMP 标准指定了归约变量的初始值。那么我是否必须初始化变量,以及在以下情况下我将如何执行此操作:
int sum;
//...
for(int it=0;i<maxIt;i++){
#pragma omp parallel
{
#pragma omp for nowait
for(int i=0;i<ct;i++)
arrayX[i]=arrayY[i];
sum = 0;
#pragma omp for reduction(+:sum)
for(int i=0;i<ct;i++)
sum+=arrayZ[i];
}
//Use sum
}
请注意,我只使用 1 个并行区域来最小化开销并允许在第一个循环中使用 nowait。按原样使用将导致数据竞争 (IMO),因为来自其他线程启动后第一个循环的线程将重置总和。
当然,我可以在外部循环的顶部执行此操作,但在一般情况下,对于大型代码库,您可能会忘记您需要或已将其设置在那里,从而产生意想不到的结果。
"omp single"在这里有帮助吗?我怀疑当线程 A 执行单个线程时,另一个线程可能已经进入缩减循环。"omp 屏障"是可能的,但我想避免这种情况,因为它击败了"nowait"。
最后再举一个例子:
#pragma omp parallel
{
sum = 0;
#pragma omp for reduction(+:sum)
for(int i=0;i<ct;i++)
sum+=arrayZ[i];
//Use sum
sum = 0;
#pragma omp for reduction(+:sum)
for(int i=0;i<ct;i++)
sum+=arrayZ[i];
//Use sum
}
我将如何在此处(重新)初始化?
编辑:这个答案是错误的,因为它做出了一个不在OpenMP规范中的假设。由于接受的答案无法删除,因此我将其留在这里作为一个例子,人们应该始终怀疑和验证在互联网上找到的代码和/或语句。
实际上,代码不会表现出数据竞赛:
#pragma omp parallel
{
...
sum = 0;
#pragma omp for reduction(+:sum)
for(int i=0;i<ct;i++)
sum+=arrayZ[i];
...
}
这里发生的情况是在工作共享构造中创建sum
的私有副本,并将其初始化为 0
(+
运算符的初始化值)。每个本地副本都由循环体更新。给定线程完成后,它将在for
构造末尾存在的隐式屏障处等待。一旦所有线程都到达屏障,它们的本地sum
副本就会相加,结果将添加到共享值中。
所有线程可能在不同的时间执行sum = 0;
并不重要,因为它的值仅在达到屏障后更新。想想上面的代码,执行如下:
...
sum = 0;
// Start of the for worksharing construct
int local_sum = 0; // ^
for(int i = i_start; i < i_end; i++) // | sum not used here
local_sum += arrayZ[i]; // v
// Implicit construct barrier
#pragma omp barrier
// Reduction
#pragma omp atomic update
sum += local_sum;
#pragma omp barrier
// End of the worksharing construct
...
这同样适用于第二个示例。
OpenMP 规范没有规定何时以及如何更新原始值,并强制要求使用同步(OpenMP,第 205 页):
若要避免争用条件,原始列表项的并发读取或更新必须与由于
reduction
计算而发生的原始列表项的更新同步。
在这两个示例中,都需要在分配给sum
后进行barrier
,或者需要一个single
构造(不带nowait
)以防止竞争条件。
- C++omp没有显著改善
- 等待整个 omp 块完成,然后再调用第二个函数
- OpenMP 加上unordered_map<字符串、双字符串的缩减>
- OpenMP #pragma omp for v/s #pragma omp parallel for 之间的区别?
- Clang,OpenMP和自定义矢量/矩阵缩减
- OpenMP 任意缩减(合并)
- 自定义 OMP 缩减 在 std::map 上
- 扩充矩阵的行缩减-三维样条曲线计算
- 函数中的"pragma omp parallel for"在另一个并行循环中调用函数时无效
- OMP for 循环,无需初始化
- 为什么在杂注 omp 关键之后多次调用 printf 会产生乱码输出?
- GSL+OMP:C++中的线程安全随机数生成器
- 在向量上声明缩减,在 1 个线程上运行给出的结果与没有 openmp 的结果不同
- 英特尔编译器 (C++) 问题与 std::vector 上的 OpenMP 缩减
- Xtensor 和 XSIMD:提高缩减性能
- OpenMP 缩减为模板指定大小的数组C++会导致未定义的行为
- 编译器是否实际使用我的"omp declare simd"函数?
- 如何在 OpenMP 中进行有序缩减
- 如何在循环内将大对象复制到omp任务中?
- 初始化变量以进行 omp 缩减