Sections Construct

sections construct是由一個sections directive再加上數個section directive所組成,其中每個section directive涵蓋一個可獨立執行的結構化程式區塊,也就是進出這些程式區塊的路徑只能有一條,而且這些區塊必須彼此獨立,執行它們並不需要按一定的順序,誰先誰後都不會影響到最後的結果,像這樣就可以使用OpenMP的sections construct來將它們平行化。

在sections construct內,每個程式區塊都會分配到一個執行緒來處理它的工作,實際的分配情形由作業系統調度來決定,我們無法決定,過程中先遭遇到某個 section任務的執行緒就負責處理該section的工作,其它的執行緒則繼續去找尚未被執行的section。如果執行緒數目大於待執行的section數目,則多出來的執行緒會被系統閒置,如果執行緒數目少於section的數目,則先完成工作的執行緒,會接著去執行尚未被處理的section任務,造成有些執行緒完成的section數量較多。

OpenMP無法自動規劃出最佳的工作量分配,這部分必須要靠開發者自己來作,舉例來說,我們可以在程式中先測量出每個獨立任務所秏費的時間,然後再修改原程式的撰寫次序,盡量將幾個比較小型的獨立任務寫在一塊,將它們分配給同一個section,整體的目標是將每個section的運算量都調整到差不多一樣的大小,再使用適量的執行緒去執行程式以減少運算資源的浪費。


sections construct屬於work-sharing constructs的一員,所以結束的地方會有一個執行緒同步點存在,sections construct並無新增執行緒的能力,所以必須嵌入在parallel construct之中才能夠平行處理程式,下圖為sections construct的運作概念:

Sections Construct


以下我們示範sections construct的用法,每個執行緒執行各自工作區塊的任務,另外使用Sleep()函式拖延完成工作的時間,這樣在平行化後才不會因為執行過快,導致只調用一個執行緒就完成sections construct內所有的任務:

#include <cstdio>
#include <cstdlib>
#include <omp.h>
#include <windows.h>

void calcSum(int);

int main(){
    int tid;
    #pragma omp parallel private(tid)
    {
        #pragma omp sections
        {
            #pragma omp section
            {
                calcSum(3);
            }
            #pragma omp section
            {
                calcSum(5);
            }
            #pragma omp section
            {
                calcSum(7);
            }
            #pragma omp section
            {
                calcSum(9);
            }
        }
    }
    system("PAUSE");
    return 0;
}

void calcSum(int n){
    int tid = omp_get_thread_num();
    int value = 0;
    for(int i=0; i<=n; i++){
        Sleep(1);
        value += i;
    }
    printf("Thread %d: sum of %d = %d\n", tid, n, value);
}

Sections Construct


sections construct與loop construct一樣可與parallel construct合併成一個複合結構,我們將上述例子改成複合結構,會得到一樣的結果:

#include <cstdio>
#include <cstdlib>
#include <omp.h>
#include <windows.h>

void calcSum(int);

int main(){ 
    int tid; 
    #pragma omp parallel sections private(tid) 
    { 
        #pragma omp section 
        { 
            calcSum(3); 
        } 
        #pragma omp section 
        { 
            calcSum(5); 
        } 
        #pragma omp section 
        { 
            calcSum(7); 
        } 
        #pragma omp section 
        { 
            calcSum(9); 
        } 
    } 
    system("PAUSE"); 
    return 0; 
}

void calcSum(int n){
    int tid = omp_get_thread_num();
    int value = 0;
    for (int i=0; i<=n; i++) {
        Sleep(1);
        value += i;
    }
    printf("Thread %d: sum of %d = %d\n", tid, n, value);
}

回到首頁

回到OpenMP教學


參考資料:

aaz 的記憶倉庫