程式扎記: [ C 文章收集 ] 簡易的程式平行化-OpenMP(三)範例 parallel、section

標籤

2014年3月7日 星期五

[ C 文章收集 ] 簡易的程式平行化-OpenMP(三)範例 parallel、section

來源自 這裡 
Preface: 
OpenMP 裡,平行化的方式有三種:parallelsectionsfor不過 section 和 for 都需要 parrallel)。這裡,舉些例子來說明他們的運作. 

parallel、section Usage: 
而用來測試的函式 Test() 內容如下: 
  1. void Test( int n )  
  2. {  
  3.   printf( " - %d\n", omp_get_thread_num(), n );  
  4. }  
首先來看 parrallel 的語法,很直接 - 就是 #pragma omp parallel;不過原則上,後面要用 { } 來指定 scope。範例程式如下: 
- t3_1.c 
  1. #include   
  2. #include   
  3. #include   
  4. int main(int argc, char* argv[])  
  5. {  
  6.     #pragma omp parallel  
  7.     {  
  8.         Test( 0 );  
  9.     }     
  10. }  
而這樣的程式在一台雙核心的電腦上,結果應該會是: 
- 0
- 0

從結果可以看出來,Test() 被兩個不同的 thread 個別執行了一次,所以會輸出兩行;這是因為 OpenMP 會根據硬體,自動選擇預設的執行緒數目. 接著,在針對程式些修改,變成: 
- t3_2.c 
  1. #include   
  2. #include   
  3. #include   
  4.   
  5. #define OMP 11  
  6.   
  7. void Test( int n )  
  8. {  
  9.     printf( " - %d\n", omp_get_thread_num(), n );  
  10. }  
  11.   
  12. int main(int argc, char* argv[])  
  13. {  
  14.     #pragma omp parallel if(OMP>10) num_threads(3)  
  15.     {  
  16.         Test(0);  
  17.     }  
  18. }  
而這樣的程式的執行結果應該會是: 
- 0
- 0
- 0

在程式中,加入了 if 和 num_threads() 這兩個語法。num_threads() 是用來指定執行緒的數目的,而在上面的程式中,把它指定成 3,所以結果會由三個不同的 thread,個別呼叫一次 Test(). 而if(OMP>10) 則是拿來控制是否要平行化的條件;如果把 #define OMP 11 改成 #define OMP 9或者任何不大於 10 的數)的話,結果就會變成 Test() 只被呼叫一次,只印出一行! 

而在 parallel 的範圍內,還有一些 directive 是可以使用的;像是 single、master 等等。像下面的程式: 
- t3_3.c 
  1. #pragma omp parallel num_threads(2)  
  2. {  
  3.     forint i = 0; i < 3; ++ i )  
  4.         Test( i );  
  5.     printf( "Hi\n" );  
  6.     #pragma omp single  
  7.     {  
  8.         printf( "Hi, single\n" );  
  9.     }  
  10.     #pragma omp master  
  11.     printf( "Hi, master\n" );  
  12. }  
執行結果: 
- 0
- 1
- 2
Hi
Hi, single
- 0
- 1
- 2
Hi
Hi, master
其中,可以發現加上 single 和 master 的部份的程式只會被執行一次;而 master 和 single 兩者間的差異,則是 master 會一定由主執行緒來執行single 不一定

sections 的用處,是把程式中沒有相關性的各個程式利用 #pragma omp section 來做區塊切割,然後由 OpenMP 做平行的處理。下面的程式是一個簡單的例子: 
- t3_4.c 
  1. #include   
  2. #include   
  3. #include   
  4.   
  5. #define OMP 3  
  6.   
  7. void Test( int n )  
  8. {  
  9.     printf( " - %d\n", omp_get_thread_num(), n );  
  10. }  
  11.   
  12. int main(int argc, char* argv[])  
  13. {  
  14. #pragma omp parallel sections  
  15.     {  
  16. #pragma omp section  
  17.         {  
  18.             forint k = 0; k < 1000000; k++ ){}  
  19.             Test( 0 );  
  20.         }  
  21. #pragma omp section  
  22.         {  
  23.             Test( 1 );  
  24.         }  
  25. #pragma omp section  
  26.         {  
  27.             Test( 2 );  
  28.         }  
  29. #pragma omp section  
  30.         {  
  31.             Test( 3 );  
  32.         }  
  33.     }  
  34. }  
而執行出來的結果,則是 
- 1
- 2
- 3
- 0

從執行的輸出結果可以發現:由於 thread 0 先執行了執行時間最久的第一個 section,而在 thread 0 結束第一個 section 前,其他三個 section 已經由其他 thread 執行結束了! 

不過利用 sections 平行化的時候,要注意程式的相依性;如果兩段程式是有相關性的話,實際上並不適合用 sections 來做平行化。下面是個錯誤的例子: 
- t3_5.c 
  1. ...  
  2. int main(int argc, char* argv[])  
  3. {  
  4.     int a[5];  
  5. #pragma omp parallel sections  
  6.     {  
  7. #pragma omp section  
  8.         {  
  9.             int k;  
  10.             forint i = 0; i < 5; ++ i )  
  11.             {  
  12.                 a[i] = i;  
  13.                 for( k = 0; k < 10000; ++ k ){}  
  14.             }  
  15.         }  
  16. #pragma omp section  
  17.         {  
  18.             forint i = 0; i < 5; ++ i )  
  19.                 printf( "%d\n", a[i] );  
  20.         }  
  21.     }  
  22. }  
因為第一個 section 的部份,執行的速度比較慢,所以當第二的 section 要列印的時候,還來不及將資料填入 a[] 裡,所以會導致錯誤. 

Supplement: 
簡易的程式平行化方法-OpenMP(一)簡介 
簡易的程式平行化-OpenMP(二)語法說明 
* 簡易的程式平行化-OpenMP(三)範例 parallel、section 
簡易的程式平行化-OpenMP(四) 範例 for 
簡易的程式平行化-OpenMP(五) 變數的平行化 
簡易的程式平行化-OpenMP clause "private" 使用時機

沒有留言:

張貼留言

網誌存檔

關於我自己

我的相片
Where there is a will, there is a way!