Openmp没有更新

时间:2013-02-15 23:36:46

标签: openmp

我正在尝试编写一个C(gcc)函数,该函数将在跨多个线程运行时计算双精度数组的最大值。我创建了一个大小为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会抱怨使用未初始化的变量。事实证明,local_max在进入for构造之前并未在所有线程中实际更新。我以为#pragma omp flush应该这样做?如果我用#pragma omp barrier替换它,一切正常。

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

3 个答案:

答案 0 :(得分:3)

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

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

mastersingle之间的细微差别在于single末尾存在隐含障碍,而master末尾没有此类障碍。此隐式屏障使所有其他线程等待,直到执行single块的线程使其到达块的末尾(除非指定了nowait子句,这将删除隐式屏障)。使用master时,必须明确添加障碍。我无法理解为什么OpenMP设计师决定master不会像single那样有隐含的障碍。

答案 1 :(得分: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;

答案 2 :(得分:0)

更好的是,只需在#pragma omp并行操作之前移动内存分配。无需冲洗,也无需单冲洗,也无需冲洗。