OpenMP 裡,平行化的方式有三種:parallel、sections、for(不過 section 和 for 都需要 parrallel)。這裡,舉些例子來說明他們的運作。
而用來測試的函式 Test() 內容如下
void Test( int n ) { printf( "<T:%d> - %dn", omp_get_thread_num(), n ); }
輸出的形式會是:
<T:thread_id> - n
parrallel
parrallel 的語法很直接,就是 #pragma omp parallel;不過原則上,後面要用 { } 來指定 scope。範例程式如下:
#include <omp.h> #include <stdio.h> #include <stdlib.h> int main(int argc, char* argv[]) { #pragma omp parallel { Test( 0 ); } system( "pause" ); }
而這樣的程式在一台雙核心的電腦上,結果應該會是:
<t:0> - 0 <t:1> - 0
從結果可以看出來,Test() 被兩個不同的 thread 個別執行了一次,所以會輸出兩行;這是因為 OpenMP 會根據硬體,自動選擇預設的執行緒數目。
接著,在針對程式些修改,變成
#include <omp.h> #include <stdio.h> #include <stdlib.h> #define OMP 11 int main(int argc, char* argv[]) { #pragma omp parallel if(OMP>10) num_threads(3) { Test( 0 ); } printf( "n==========================nn" ); system( "pause" ); }
而這樣的程式在一台雙核心的電腦上,結果應該會是:
<t:0> - 0 <t:2> - 0 <t:1> - 0
在程式中,加入了 if 和 num_threads() 這兩個語法。num_threads() 是用來指定執行緒的數目的,而在上面的程式中,把它指定成 3,所以結果會由三個不同的 thread,個別呼叫一次 Test()。
而 if(OMP>10) 則是拿來控制是否要平行化的條件;如果把 #define OMP 11 改成 #define OMP 9(或者任何不大於 10 的數)的話,結果就會變成 Test() 只被呼叫一次,只印出一行。
而在 parallel 的範圍內,還有一些 directive 是可以使用的;像是 single、master 等等。像下面的程式
#pragma omp parallel num_threads(2) { for( int i = 0; i < 3; ++ i ) Test( i ); printf( "Hin" ); #pragma omp single { printf( "Hi, singlen" ); } #pragma omp master printf( "Hi, mastern" ); }
執行結果:
<t:0> - 0 <t:1> - 0 <t:0> - 1 <t:1> - 1 <t:0> - 2 <t:1> - 2 Hi Hi Hi, single Hi, master
其中,可以發現加上 single 和 master 的部份的程式只會被執行一次;而 master 和 single 兩者間的差異,則是 master 會一定由主執行緒來執行,single 不一定。
基本上,Heresy 不大確定什麼時候會直接用到 parrallel,所以也就不多加著墨了。(什麼時候會要把一般的程式多執行幾次啊? @@)
sections
sections 的用處,是把程式中沒有相關性的各個程式利用 #pragma omp section 來做區塊切割,然後由 OpenMP 做平行的處理。下面的程式是一個簡單的例子:
int main(int argc, char* argv[]) { #pragma omp parallel sections { #pragma omp section { for( int k = 0; k < 100000; ++ k ) {} Test( 0 ); } #pragma omp section { Test( 1 ); } #pragma omp section { Test( 2 ); } #pragma omp section { Test( 3 ); } } }
而執行出來的結果,則是:
<T:1> - 1 <T:1> - 2 <T:1> - 3 <T:0> - 0
從執行的輸出結果可以發現:由於 thread 0 先執行了執行時間最久的第一個 section,而在 thread 0 結束第一個 section 前,其他三個 section 已經由 thread 1 執行結束了~
不過利用 sections 平行化的時候,要注意程式的相依性;如果兩段程式是有相關性的話,實際上並不適合用 sections 來做平行化。下面是個錯誤的例子:
int a[5]; #pragma omp parallel sections { #pragma omp section { int k; for( int i = 0; i < 5; ++ i ) { a[i] = i; for( k = 0; k < 10000; ++ k ) {} } } #pragma omp section { for( int i = 0; i < 5; ++ i ) printf( "%dn", a[i] ); } }
其中,程式裡 for( k = 0; k < 10000; ++ k ){} 的目的只是在拖慢時間。輸出結果是:
0 1 -858993460 -858993460 -858993460
這是因為第一個 section 的部份,執行的速度比較慢,所以當第二的 section 要列印的時候,還來不及將資料填入 a[] 裡,所以會導致錯誤。
參考資料:
- MSDN 的 OpenMP:http://msdn2.microsoft.com/en-us/library/tt15eb9t.aspx
目錄:
[…] 的 task 和 section 其實有點像,都算是將不同的工作分給不同的 thread […]
讚讚
[…] thread、來進行不同的、獨立的計算;像是 OpenMP 的「section」(參考),就是屬於「task […]
讚讚
[…] 簡易的程式平行化-OpenMP(三)範例 parallel、section […]
讚讚
[…] ← 簡易的程式平行化-OpenMP(三)範例 parallel、section 小さなてのひら […]
讚讚
[…] 簡易的程式平行化-OpenMP(三)範例 parallel、section […]
讚讚
[…] 簡易的程式平行化-OpenMP(三)範例 parallel、section […]
讚讚
您好,
我是用 mingw + gcc 來使用 openmp,我製作了一個 dll,在 dll 內只有一個下面的 function
DLL_EXPORT void __stdcall Test(Byte *Source, int size)
{
#pragma omp parallel for
for(int i=0; i<size; i++)
{
if(Source[i] == 5)
Source[i] = 22;
}
}
我用 bcb 寫了個測試程式,測試如下:
主程式執行 Test() ,功能正常
主程式內新增一個 Thread,在 Thread 內 執行 Test() ,這時候就一定會當掉
openmp 不能在 Thread 內呼叫嗎?
謝謝您
讚讚
您好,Heresy 自己沒有用過使用過 mingw + gcc 的環境,也沒有把程式封包成 DLL 的經驗。
不過在 MSVC 和 GCC 下,應該都是可以在 pThread 開啟新的 thread 裡面,呼叫有使用 OpenMP 的程式的,這種寫法 Heresy 這邊目前有在使用,應該沒問題才對。
讚讚
您好又確認了一下,看來應該是以前測試的時候不知道哪裡出問題了…的確在執行#pragma omp parallelTest( 3 );時還是會平行化進行的。文章內容有問題的部分也先抽掉了。
讚讚
我在執行下面的範例時, Test(3)的結果沒有因為Test( 2 )關閉平行化而只有一個thread,他還是多個thread在執行??#pragma omp parallelTest( 1 );#pragma omp parallel if(false)Test( 2 );#pragma omp parallelTest( 3 );
讚讚