Fla*_*ire 1 c++ for-loop openmp 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
}
Run Code Online (Sandbox Code Playgroud)
请注意,我只使用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
}
Run Code Online (Sandbox Code Playgroud)
我将如何(重新)初始化?
编辑:这个答案是错误的,因为它假设不在OpenMP规范中.由于接受的答案无法删除,我将其留在这里作为一个例子,一个人应该总是怀疑和验证在互联网上找到的代码和/或语句.
实际上,代码没有展示数据竞赛:
#pragma omp parallel
{
...
sum = 0;
#pragma omp for reduction(+:sum)
for(int i=0;i<ct;i++)
sum+=arrayZ[i];
...
}
Run Code Online (Sandbox Code Playgroud)
这里发生的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
...
Run Code Online (Sandbox Code Playgroud)
这同样适用于第二个例子.