2011-12-16 105 views
1

我想寫一個函數,它使用openMP並行性,但應該工作,無論是否在並行區域內調用。所以我用了if子句來抑制並行,但我認爲這並不工作:避免嵌套並行區域

#include <omp.h> 
#include <stdio.h> 

int m=0,s=0; 

void func() 
{ 
    bool p = omp_in_parallel(); 
    // if clause to suppress nested parallelism 
#pragma omp parallel if(!p) 
    { 
    /* do some massive work in parallel */ 
#pragma omp master 
    ++m; 
#pragma omp single 
    ++s; 
    } 
} 

int main() 
{ 
    fprintf(stderr,"running func() serial:\n"); 
    m=s=0; 
    func(); 
    fprintf(stderr," m=%d s=%d\n",m,s); 

    fprintf(stderr,"running func() parallel:\n"); 
    m=s=0; 
#pragma omp parallel 
    func(); 
    fprintf(stderr," m=%d s=%d\n",m,s); 
} 

其創建的輸出

running func() serial: 
m=1 s=1 
running func() parallel: 
m=16 s=16 

因此,要func()第一個呼叫工作得很好:ms儘可能地獲得值1,但是在並行區域內第二次調用func()確實會創建嵌套並行(即每個線程有16個團隊),儘管這被抑制了。那就是omp masteromp single指令綁定到之前的omp parallel if(!p)指令,而不是綁定到外部並行區域。

當然,人們可以通過下面的代碼

void work() 
{ 
    /* do some massive work in parallel */ 
#pragma omp master 
    ++m; 
#pragma omp single 
    ++s; 
} 

void func() 
{ 
    if(omp_in_parallel()) 
    work(); 
    else 
#pragma omp parallel 
    work(); 
} 

解決這個問題,但是這需要一個附加功能進行定義等是否有可能在單個函數內做到這一點(和不重複的代碼) ?

回答

2

OpenMP構造將始終綁定到最內層包含構造,即使它不是活動的。所以我不認爲這是可能的,同時保留兩個代碼路徑#pragma omp parallel(至少與提供有關問題的信息)。

請注意,這是一個很好的想法,因爲否則使用條件很容易導致非常有問題的(讀取越野車)代碼。請看下面的例子:

void func(void* data, int size) 
{ 
    #pragma omp parallel if(size > 1024) 
    { 
     //do some work 
     #pragma omp barrier 
     //do some more work 
    } 
} 

... 
#pragma omp parallel 
{ 
    //create foo, bar, bar varies massively between different threads (so sometimes bigger, sometimes smaller then 1024 
    func(foo, bar); 
    //do more work 
} 

一般程序員不應該需要知道調用的函數的實現細節,只是他們的行爲。所以我真的不應該在意func是否創建了嵌套的parallel部分,以及它在哪個確切條件下創建一個。但是如果barrier綁定到外部parallel如果內部是不活動的這個代碼將是越野車,因爲外部parallel部分的某些線程遇到barrier而有些則不。因此,這些細節保持隱藏在最內層parallel的內部,即使它不是活動的。

就我個人而言,我從來沒有遇到過我希望它的行爲不同的情況(這會違背信息隱藏等),所以也許你應該告訴我們更多關於你想要獲得更好答案的內容。

0

我看了一下openMP標準。 if條款實際上有些誤導性地提出,因爲#pragma omp parallel指令不是有條件的(正如我原先的想法)。相反,if子句可能會將線程數限制爲1,從而抑制並行化。

但是,這意味着omp singleomp master不能用於線程安全每進程一次寫入全局共享變量。

+0

是的,它確實意味着它並不適用於此,因爲通常不能保證(信息隱藏和全部)在外層沒有嵌套並行性。對共享變量進行訪問threadsafe更像是互斥體的用例(omp中的鎖)。你的描述你想如何工作聽起來沒有什麼用處(如果有多個線程調用`do_func`,你只需要其中一個線程(因此調用)寫入全局變量?我不知道你的具體情況,但這聽起來不太有用。 – Grizzly 2011-12-23 02:14:03