Openmp没有更新

问题描述:

我试着编写一个C(gcc)函数,它将在多线程中运行时计算双精度数组的最大值。我创建了一个大小为omp_get_num_threads的数组,其中我存储了每个线程的局部最大值,然后才最终使这个小数组最大化。该代码是(或多或少)以下:Openmp没有更新

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代替它,一切正常。

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

您需要设置屏障来确保内存分配已完成。内存分配是一项耗时的操作,当您的最终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; 
+0

非常感谢你,这很有道理。我遇到的一个后续问题是,当线程遇到'flush'构造时,是否所有线程同时进行同步?他们在哪里恢复执行? – Ivan 2013-02-16 00:44:30

+0

'flush'是一个棘手的问题,并且倾向于让我们认为所有的线程都会停止并同步,然后所有的线程都会继续愉快地执行。但这是错误的。当线程遇到'flush'时,它会同步并恢复执行。您可以使用omp_get_wtime来打印执行时间,并在代码中添加一些随机睡眠呼叫,以查看其执行方式。我建议你避免使用'flush',因为它增加了相当高的复杂性。 – ikikenis 2013-02-16 01:06:58

+0

这是否意味着其他线程不会与遇到'flush'的同时同步?他们在访问一个变量的过程中是什么,但在并行构造的不同部分呢? – Ivan 2013-02-16 01:20:30

您的问题,最简单的方法是简单地用一个single一个替代master结构,因为它并不真正的问题是哪个线程将使分配(除非你是一个NUMA机器上运行,但你也有很多其他的事情担心):

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

mastersingle之间的细微差别是,有在single结束的隐式屏障,而没有这种障碍在master末存在。这个隐式屏障使所有其他线程等待,直到执行块的线程已经到达块的末尾(除非指定了nowait子句,这将删除隐式屏障)。使用master必须明确添加屏障。这超出了我的理解,为什么OpenMP设计人员做出这样的决定:master不会像single那样具有隐含的障碍。