2011-01-05 70 views
0

我有一個for循環,使用(有點複雜)的計數器對象sp_ct來初始化一個數組。串行代碼看起來像優雅地初始化循環openmp線程

sp_ct.depos(0); 
for(int p=0;p<size; p++, sp_ct.increment()) { 
    in[p]=sp_ct.parable_at_basis(); 
} 

我的計數器支持並行化,因爲它可以後p增量初始化狀態,導致下面的工作代碼片段:

int firstloop=-1; 
#pragma omp parallel for \ 
     default(none) shared(size,in) firstprivate(sp_ct,firstloop) 
    for(int p=0;p<size;p++) { 
    if(firstloop == -1) { 
     sp_ct.depos(p); firstloop=0; 
    } else { 
     sp_ct.increment(); 
    } 
    in[p]=sp_ct.parable_at_basis(); 
    } // end omp paralell for 

我不喜歡因爲這混亂,它掩蓋了真正發生的事情,並且因爲它在循環中有一個不必要的分支(是的,我知道這對於運行時間可能沒有可測量的影響,因爲它是,所以可預測......)。

我寧願寫類似

#pragma omp parallel for default(none) shared(size,in) firstprivate(sp_ct,firstloop) 
    for(int p=0;p<size;p++) { 
#prgma omp initialize // or something 
    { sp_ct.depos(p); } 
    in[p]=sp_ct.parable_at_basis(); 
    sp_ct.increment(); 
    } 
    } // end omp paralell for 

這可能嗎?

+0

有沒有理由不能在循環之外進行初始化? – 2011-01-05 23:56:36

+1

是的,初始化取決於分配給該線程的第一個「p」值。這在循環之外是未知的。 – 2011-01-06 00:05:38

回答

0

我明白你想要做什麼,我不認爲這是可能的。我只是想寫一些我相信會達到同樣目的的代碼,並且有點乾淨,如果你喜歡它,那麼甜美!

sp_ct.depos(0); 
in[0]=sp_ct.parable_at_basis(); 
#pragma omp parallel for \ 
     default(none) shared(size,in) firstprivate(sp_ct,firstloop) 
    for(int p = 1; p < size; p++) { 
    sp_ct.increment(); 
    in[p]=sp_ct.parable_at_basis(); 
    } // end omp paralell for 
+0

您必須編輯#pragma語句,我確定。 (我真的不知道openmp,對不起) – 2011-01-06 00:30:32

+0

是的,這正是我的問題:你可以在'#pragma'中以某種方式進行初始化嗎? – 2011-01-06 00:31:58

+0

我不知道,對不起,我無法回答你的問題。我可以問你爲什麼需要這樣做? – 2011-01-06 00:47:27

1

如果我推廣你的問題,問題是「如何執行平行部分的每個線程的初始化代碼?」,是嗎?您可以使用firstprivate子句的屬性:「給定變量的初始化或構造發生,就像在線程執行構造之前每個線程完成一次一樣」。

struct thread_initializer 
{ 
    explicit thread_initializer(
    int size /*initialization params*/) : size_(size) {} 

    //Copy constructor that does the init 
    thread_initializer(thread_initializer& _it) : size_(_it.size) 
    { 
    //Here goes once per thread initialization 
    for(int p=0;p<size;p++) 
     sp_ct.depos(p); 
    } 

    int size_; 
    scp_type sp_ct; 
}; 

然後循環可以寫成:

thread_initializer init(size); 
#pragma omp parallel for \ 
     default(none) shared(size,in) firstprivate(init) 
for(int p=0;p<size;p++) { 
    init.sp_ct.increment(); 
} 
in[p]=init.sp_ct.parable_at_basis(); 

不好的東西,你必須寫這個額外的初始化和一些代碼被移離其實際執行點之遙。好處是您可以重複使用它以及更簡潔的循環語法。

0

Riko,執行sp_ct.depos(),因此只會根據需要調用.increment()以使計數器達到傳遞的參數。然後你可以使用此代碼:

sp_ct.depos(0); 
#pragma omp parallel for \ 
     default(none) shared(size,in) firstprivate(sp_ct) 
for(int p=0;p<size;p++) { 
    sp_ct.depos(p); 
    in[p]=sp_ct.parable_at_basis(); 
} // end omp paralell for 

這個方案有一個額外的好處:你的實現只有當每個線程只接收一個塊出0 - size工作。指定schedule(static)省略塊大小時(OpenMP 4.0 Specification,章節2.7.1,第57頁),情況如此。但由於您未指定schedule,所用的時間表將取決於實施(OpenMP 4.0 Specification,章節2.3.2)。如果實現選擇使用dynamicguided,則線程將收到多個塊,它們之間有間隙。所以一個線程可能會收到數據塊0-20,然後數據塊70-90,這會使第二個數據塊上的psp_ct不同步。上述解決方案與所有時間表兼容。

1

從我可以告訴你可以做到這一點,通過手動定義塊。這看起來有點像的東西,我想用感應做OpenMP中Induction with OpenMP: getting range values for a parallized for loop in OpenMP

所以,你可能想是這樣的:

#pragma omp parallel 
{ 
    const int nthreads = omp_get_num_threads(); 
    const int ithread = omp_get_thread_num(); 
    const int start = ithread*size/nthreads; 
    const int finish = (ithread+1)*size/nthreads;  
    Counter_class_name sp_ct; 

    sp_ct.depos(start); 
    for(int p=start; p<finish; p++, sp_ct.increment()) { 
     in[p]=sp_ct.parable_at_basis(); 
    } 
} 

注意,除了一些聲明和改變範圍值這個代碼幾乎是相同的到串行代碼。

此外,您不必聲明任何共享或私有。在並行塊內聲明的所有內容都是私有的,並且外部聲明的內容都是共享的你也不需要firstprivate。這使得代碼更清晰和更清晰(恕我直言)。