0

我正在尝试编写一个 C (gcc) 函数,该函数将在跨多个线程运行时计算双精度数组的最大值。我创建了一个 size 数组omp_get_num_threads,在最终最大化这个小数组之前,我在其中存储了每个线程的局部最大值。代码(或多或少)如下:

int i;
double *local_max;
double A[1e10]; //made up size

#pragma omp parallel
{

#pragma omp master
{
local_max=(double *)calloc(omp_get_num_threads(),sizeof(double));
}

#pragma omp flush  //so that all threads point 
                   //to the correct location of local_max

#pragma omp for

for(i=0;i<1e10;i++){
   if(A[i]>local_max[omp_get_thread_num()])
      local_max[omp_get_thread_num()]=A[i];
}

}

free(local_max);

然而,这会导致段错误,并且 valgrind 抱怨使用了未初始化的变量。for事实证明,在所有线程进入构造之前,local_max 实际上并未在所有线程中更新。我想#pragma omp flush应该这样做吗?如果我用 替换它#pragma omp barrier,一切正常。

有人可以向我解释发生了什么吗?

4

3 回答 3

3

解决您的问题的最简单方法是简单地将master结构替换为single一个,因为哪个线程会进行分配并不重要(除非您在 NUMA 机器上运行,但是您还有许多其他事情要担心):

#pragma omp single
{
   local_max=(double *)calloc(omp_get_num_threads(),sizeof(double));
}

master和之间的细微差别在于single,在结尾处有一个隐含的障碍,single而在结尾处不存在这样的障碍master。这个隐式屏障使所有其他线程等待,直到执行single块的线程到达块的末尾(除非nowait指定了子句,它删除了隐式屏障)。master必须明确添加屏障。我无法理解为什么 OpenMP 设计者会做出这样的决定,master而不会像现在这样有隐含的障碍single

于 2013-02-18T20:40:01.983 回答
1

您需要设置屏障以确保内存分配已完成。内存分配是一项耗时的操作,当您的最终 for 循环开始运行时,local_max 未指向正确分配的空间。我在下面修改了您的代码以演示该行为。

int i;
double *local_max;
omp_set_num_threads(8);
#pragma omp parallel
{
#pragma omp master
    {           
        for(int k = 0; k < 999999; k++) {} // Lazy man's sleep function
        cout << "Master start allocating" << endl;
        local_max=(double *)calloc(omp_get_num_threads(),sizeof(double));
        cout << "Master finish allocating" << endl;
    }
#pragma omp flush 
#pragma omp for
    for(i=0;i<10;i++){
        cout << "for : " << omp_get_thread_num()  << " i: " << i << endl;
    }
}
free(local_max);
getchar();
return 0;
于 2013-02-16T00:41:03.363 回答
0

更好的是,只需在#pragma omp 并行之前移动内存分配。不需要冲洗,或单,或主。

于 2020-09-30T22:15:13.747 回答