2013-02-15 67 views
0

我試着編寫一個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代替它,一切正常。

有人可以向我解釋發生了什麼事嗎?

回答

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; 
+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

3

您的問題,最簡單的方法是簡單地用一個single一個替代master結構,因爲它並不真正的問題是哪個線程將使分配(除非你是一個NUMA機器上運行,但你也有很多其他的事情擔心):

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

mastersingle之間的細微差別是,有在single結束的隱式屏障,而沒有這種障礙在master末存在。這個隱式屏障使所有其他線程等待,直到執行塊的線程已經到達塊的末尾(除非指定了nowait子句,這將刪除隱式屏障)。使用master必須明確添加屏障。這超出了我的理解,爲什麼OpenMP設計人員做出這樣的決定:master不會像single那樣具有隱含的障礙。