OpenMP 的减少是否可以避免错误共享?

Sus*_*lik 3 c++ openmp

我还是很困惑。如果我在 OpenMP 中使用 reduce 子句会发生错误共享吗?(两个代码片段都给出了正确的结果。)

一个小例子,其中需要数组的最大值:

double max_red(double *A, int N){

double mx = std::numeric_limits<double>::min();
#pragma omp parallel for reduction(max:mx)
for(int i=0; i<N; ++i){
    if(A[i]>mx) mx = A[i];

}

return mx; 
}
Run Code Online (Sandbox Code Playgroud)

这个例子也可以用额外的填充来编写

double max_padd(double *A, int N){

omp_set_num_threads(NUM_THREADS);
double local_max[NUM_THREADS][8];
double res;

#pragma omp parallel
{

    int id = omp_get_thread_num();
    local_max[id][0] = std::numeric_limits<double>::min();

    #pragma omp for
        for(int i=0; i<N; ++i){
            if(A[i]>local_max[id][0])local_max[id][0]=A[i];
    }
    #pragma omp single
    {
        res = local_max[0][0];
        for(int i=0; i<NUM_THREADS; ++i){
            if(local_max[i][0]> res)res = local_max[i][0];
        }
    }
}

return res;
Run Code Online (Sandbox Code Playgroud)

}

但是完全禁止虚假共享所需的额外填充还是减少条款足够安全?

谢谢

Zul*_*lan 5

填充不是必需的。

从技术上讲,这不是标准规定的。该标准没有说明每个线程私有副本在内存中的位置。请记住,错误共享不是正确性问题,而是(非常重要的)实际性能问题。

但是,如果任何 OpenMP 实现会犯这样一个新手错误并将私有副本放在同一缓存行上,那将是非常令人惊讶的。

假设实现比程序员更了解平台及其性能特征。如果您通过测量证明惯用解决方案(例如您的第一个解决方案)具有无法通过调整修复的不良性能,则仅编写手动“性能改进”,例如您的第二个解决方案。

实用说明:我相当确定实现通常会将私有副本放在执行线程的(私有)堆栈上,然后每个线程将使用临界区或在支持时以原子方式更新共享变量。

理论上,基于对数时间树的缩减是可能的。然而,实现似乎并没有这样做,至少不是在所有情况下。