OpenMP入門教程(三)


承接前面兩篇,這里直接逐一介紹和使用有關OpenMP的指令和函數

 

Directives

1、for 

作用:for指令指定緊隨其后的程序的循環的迭代必須由團隊並行執行,只是假設已經建立了並行區域,否則它在單個處理器上串行執行。

格式:

 1 #pragma omp for [clause ...] newline 
 2                 schedule (type [,chunk]) 
 3                 ordered 
 4                 private (list) 
 5                 firstprivate (list) 
 6                 lastprivate (list) 
 7                 shared (list) 
 8                 reduction (operator:list) 
 9                 collapse (n) 
10                 nowait for_loop

可以使用如下子句:

還可以通過Schedule子句(clause)設置for循環的並行化方法:(有關一種調度如何比其他調度更優化的討論,請參閱http://openmp.org/forum/viewtopic.php?f=3&t=83

  • static:循環迭代被分成size chunk,然后靜態的分配給各個線程,如果chunk沒有被指定,則均勻地划分(如果可能)給各個線程
  • dynamic:循環迭代被分成size chunk,然后動態地分配給各個線程,當一個chunk完成時,被分配另外一個chunk。默認地chunk size為1
  • guided:當線程請求循環迭代時,迭代會動態地分配給塊中地線程,直到沒有剩余的塊要被分配。與dynamic類似,不同的地方在於每次為線程分配chunk時都會變小,所以最初組中的循環體執行數目較大。初始大小與以下成正比,number_of_iterations / number_of_thread,后續塊與之成比例,number_of_iterations_remaining / number_of_threads。
  • runtime: 循環的並行化方式不在編譯時靜態確定,而是推遲到程序執行時動態地根據環境變量OMP_SCHEDULE 來決定要使用的方法。此時在子句中指定chunk_size是非法的
  • auto:調度決策取決於編譯器/運行時系統  

nowait子句:如果指定,則線程在循環結束時不同步

ordered子句:指定必須像在串行程序中一樣執行循環的迭代,可以對for的部分使用

collapse子句:指定嵌套循環中應將多少循環折疊到一個大的迭代空間中,並根據schedule子句進行划分 。折疊迭代空間中的迭代順序被確定為順序執行它們。可以改善表現。

其它的子句后面會做介紹

限制:

  • 循環迭代變量必須是整數,並且所有線程的循環控制參數必須相同
  • 程序正確性不能取決於哪個線程執行特定迭代,需要確保程序的正確性
  • 從for指令關聯的循環中分支是非法的
  • 必須將塊大小指定為循環不變整數表達式,因為在不同線程的評估期間沒有同步

示例

 1  #include <omp.h>
 2  #define N 1000
 3  #define CHUNKSIZE 100
 4 
 5  main(int argc, char *argv[]) {
 6 
 7  int i, chunk;
 8  float a[N], b[N], c[N];
 9 
10  /* Some initializations */
11  for (i=0; i < N; i++)
12    a[i] = b[i] = i * 1.0;
13  chunk = CHUNKSIZE;
14 
15  #pragma omp parallel shared(a,b,c,chunk) private(i)
16    {
17 
18    #pragma omp for schedule(dynamic,chunk) nowait
19    for (i=0; i < N; i++)
20      c[i] = a[i] + b[i];
21 
22    }   /* end of parallel region */
23 
24  }

2、section

作用:section是一種非迭代的工作共享結構,代碼被划分成多個區域

格式:

 1 #pragma omp sections [clause ...]  newline 
 2                      private (list) 
 3                      firstprivate (list) 
 4                      lastprivate (list) 
 5                      reduction (operator: list) 
 6                      nowait
 7   {
 8 
 9   #pragma omp section   newline 
10 
11      structured_block
12 
13   #pragma omp section   newline 
14 
15      structured_block
16 
17   }

注意:

  • 除非使用nowait子句,否則sections指令結尾都有一個隱含的障礙
  • 分區塊里不能含有分支

示例

 1  #include <omp.h>
 2  #define N 1000
 3 
 4  main(int argc, char *argv[]) {
 5 
 6  int i;
 7  float a[N], b[N], c[N], d[N];
 8 
 9  /* Some initializations */
10  for (i=0; i < N; i++) {
11    a[i] = i * 1.5;
12    b[i] = i + 22.35;
13    }
14 
15  #pragma omp parallel shared(a,b,c,d) private(i)
16    {
17 
18    #pragma omp sections nowait
19      {
20 
21      #pragma omp section
22      for (i=0; i < N; i++)
23        c[i] = a[i] + b[i];
24 
25      #pragma omp section
26      for (i=0; i < N; i++)
27        d[i] = a[i] * b[i];
28 
29      }  /* end of sections */
30 
31    }  /* end of parallel region */
32 
33  }

3、其它的不一一介紹了,請參閱:OpenMP

 

Clause

前面已經介紹了幾個子句,這里主要介紹數據作用域子句。

1、private

作用:private子句將其列表中的變量聲明為每個線程的私有變量

格式:

private (list)

要點:

  • 在組中的每個線程聲明一個相同數據類型的變量
  • 所有對原始變量的引用全部替換為對新變量的引用
  • 被聲明為private的變量應被認為未初始化

2、shared

作用:shared子句聲明其列表中的變量,以便在團隊中的所有線程之間共享

格式:

shared (list)

要點:

  • 共享變量僅存在於一個內存位置,並且所有線程都可以讀取或寫入該地址
  • 程序員有責任確保多個線程正確訪問SHARED變量(例如通過CRITICAL部分)

3、reduction

作用:reduction子句對列表中的每個變量執行簡化操作。為每個線程創建並初始化每個列表變量的私有副本。在縮減結束時,reduce變量應用於共享變量的所有私有副本,最終結果將寫入全局共享變量。

格式:

1 reduction (operator: list)

示例:

並行循環的迭代將以相同大小的塊分配給團隊中的每個線程(SCHEDULE STATIC);

在並行循環結構的末尾,所有線程將添加其“result”值以更新主線程的全局副本;

 1 #include <omp.h>
 2 
 3  main(int argc, char *argv[])  {
 4 
 5  int   i, n, chunk;
 6  float a[100], b[100], result;
 7 
 8  /* Some initializations */
 9  n = 100;
10  chunk = 10;
11  result = 0.0;
12  for (i=0; i < n; i++) {
13    a[i] = i * 1.0;
14    b[i] = i * 2.0;
15    }
16 
17  #pragma omp parallel for      \  
18    default(shared) private(i)  \  
19    schedule(static,chunk)      \  
20    reduction(+:result)  
21 
22    for (i=0; i < n; i++)
23      result = result + (a[i] * b[i]);
24 
25  printf("Final result= %f\n",result);
26 
27  }

4、其它還有很多,省略

 

Run-time Library Routines

  • OpenMP API包含越來越多的運行時庫例程
  • 對於C / C ++,所有運行時庫例程都是實際的子例程。對於Fortran,有些實際上是函數,有些是子例程。
  • 對於C / C ++,通常需要包含 <omp.h>頭文件

例如:

1 #include <omp.h> 
2 int omp_get_num_threads(void

詳細的函數介紹可見OpenMP入門教程(二)

 

Environment Variables

  • OpenMP提供一些環境變量來控制並行程序的執行
  • 所有的環境變量名都是大寫字母,但是分配給它們的值不區分大小寫

1、OMP_NUM_THREADS:設置在運行期間最大的線程數

setenv OMP_NUM_THREADS 8

2、OMP_DYNAMIC啟用或禁用動態調整可用於執行並行區域的線程數。有效值為TRUE或FALSE

setenv OMP_DYNAMIC TRUE

3、OMP_PROC_BIND啟用或禁用綁定到處理器的線程。有效值為TRUE或FALSE。

setenv OMP_PROC_BIND TRUE

4、OMP_STACKSIZE:控制創建(非主)線程的堆棧大小

setenv OMP_STACKSIZE 2000500B 
setenv OMP_STACKSIZE“3000 k” 
setenv OMP_STACKSIZE 10M 
setenv OMP_STACKSIZE“10 M” 
setenv OMP_STACKSIZE“20 m” 
setenv OMP_STACKSIZE“1G” 
setenv OMP_STACKSIZE 20000

4、還有很多其它的,省略

注:前面的運行API也能做與環境變量一樣的工作,同時使用環境變量和運行時 API 會出現什么情況?運行時 API 將獲得更高的優先權。

注:這是一個簡單的OpenMP的練習網站:https://computing.llnl.gov/tutorials/openMP/exercise.html

 

 

 

參考鏈接:https://computing.llnl.gov/tutorials/openMP/#Abstract

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM