我还是一头雾水。如果我在 OpenMP 中使用 reduction 子句,是否会发生错误共享? (两个代码片段都给出了正确的结果。)
一个小例子,其中需要一个数组的最大值:
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;
}
这个例子也可以用额外的填充来写
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;
但是完全禁止虚假共享是否需要额外的填充,或者减少条款是否足够安全?
谢谢
最佳答案
填充不是必需的。
从技术上讲,这不是标准强制要求的。该标准没有说明每个线程私有(private)拷贝在内存中的位置。请记住,错误共享不是正确性问题,而是(非常重要的)实际性能问题。
但是,如果任何 OpenMP 实现会犯这样的菜鸟错误并将私有(private)拷贝放在同一缓存行上,那将是非常令人惊讶的。
假设实现比程序员更了解平台及其性能特征。如果您通过测量证明惯用解决方案(例如您的第一个解决方案)具有无法通过调优修复的不良性能,则仅编写手动“性能改进”,例如您的第二个解决方案。
实用说明:我相当确定实现通常会将私有(private)拷贝放在执行线程的(私有(private))堆栈上,然后每个线程都会使用关键部分或在支持时以原子方式更新共享变量。
理论上,基于对数时间树的缩减是可能的。然而implementations don't seem to do that ,至少不是在所有情况下。
关于c++ - 减少 OpenMP 是否可以避免虚假共享?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49630440/