天天看點

OpenMP 參考 (指令格式)

OpenMP 指令格式

C / C++ 指令格式

格式:
#pragma omp directive-name [clause, ...] newline
 OpenMP C/C++ 指令都需要. 有效OpenMP 指令. 必須在pragma指令後,在 clauses指令前。 可選. 除非有另外的限制,子句可以任意順序, 根據需要重複。 必需. 位于被這個指令包圍的結構塊之前。

示例:

#pragma omp parallel default(shared) private(beta,pi)      

規則:

  • 區分大小寫
  • 指令遵守C/C++編譯器指令标準
  • 每條指令隻能有一個指令名稱
  • 每條指令适用于最少一條被結構塊包圍的語句
  • 常指令可以在一條指令行結束後,用"/"連接配接

Fortran 指令格式

格式: (不區分大小寫)

sentinel directive-name [clause ...]
所有的Fortan OpenMP指令必須以哨兵開始。 接受的哨兵依賴于Fortan源程式。可能的形式:
    !$OMP      
    C$OMP      
    *$OMP       
有效OpenMP指令,必須在哨兵和子句之間。  可選.除非有另外的限制,子句可以任意順序, 根據需要重複。

示例:

!$OMP PARALLEL DEFAULT(SHARED) PRIVATE(BETA,PI)      

固定格式源:

  • !$OMP C$OMP *$OMP 作為接受的哨兵,必須出現在第一列 
  • 所有Fortan的固定規則,比如行長度,空格,繼續,注釋等,對整條指令都适合 
  • 初始指令行必須在第六列包含一個空格/0
  • 接下來的指令行在第六列必須包含一個非空格/0 

自由格式源:

  • !$OMP 是唯一的接受哨兵. 可以出現在任何列,但必須前面隻能有空格 
  • 所有Fortan的自由規則,比如行長度,空格,繼續,注釋等,對整條指令都适合 
  • 初始指令行之後必須有個空格
  • 後續行的每一行,最後都必須有個作為非空白字元的符号

規則:

  • 注釋不能作為指令出現在同一行
  • 每條指令隻能指定一個指令名稱
  • 啟用了OpenMP的Fortran編譯器通常包含一條指令行選項,用來訓示編譯器激活并解釋所有的OpenMP指令 
  • 幾個Fortran OpenMP指令成對出現,格式如下所示. "end"是可選的,但為了提高可讀性,建議不要省略.
!$OMP  directive       
    [ structured block of code ]      
!$OMP end  directive      
OpenMP 指令

指令作用域

不羅嗦了...

靜态範圍:

  • 代碼由一條OpenMP的指令開頭,寫在一個結構塊的開始和結束之間
  • 指令的靜态範圍不能跨越多個例程或代碼檔案

孤立指令:

  • 看起來和另外一個包圍指令沒有關系的指令被稱為孤立指令。 它存在于另外一個指令的靜态範圍之外。
  • 跨越多個例程(也許是代碼檔案)

Dynamic Extent動态範圍:

  • 指令的動态範圍包括它的靜态範圍以及孤立指令範圍.

Example:

      PROGRAM TEST      
      ...      
!$OMP PARALLEL      
      ...      
!$OMP DO      
      DO I=...      
      ...      
      CALL SUB1      
      ...      
      ENDDO      
      ...      
      CALL SUB2      
      ...      
!$OMP END PARALLEL      
      SUBROUTINE SUB1      
      ...      
!$OMP CRITICAL      
      ...      
!$OMP END CRITICAL      
      END      
      SUBROUTINE SUB2      
      ...      
!$OMP SECTIONS      
      ...      
!$OMP END SECTIONS      
      ...      
      END      

靜态範圍 

并行區域内的DO 指令

孤立指令 

并行區域外的CRITICAL 和SECTIONS 指令

動态範圍 

CRITICAL 和SECTIONS 指令在DO 和PARALLEL 指令的動态範圍内.

為什麼這一點很重要?

  • OpenMP 制定了一系列關于指令關聯(綁定)與嵌套的範圍規則
  • 如果OpenMP的綁定與嵌套規則被忽略,可能導緻程式非法或不正确
  • 有關細節請參考Directive Binding and Nesting Rules 

并行區域結構

作用:

  • 并行區域是一塊能被多個線程執行的代碼。下面是基本的OpenMP并行結構:

格式:

Fortran
!$OMP PARALLEL [clause ...]       
               IF (scalar_logical_expression)       
               PRIVATE (list)       
               SHARED (list)       
               DEFAULT (PRIVATE | FIRSTPRIVATE | SHARED | NONE)       
               FIRSTPRIVATE (list)       
               REDUCTION (operator: list)       
               COPYIN (list)       
               NUM_THREADS (scalar-integer-expression)      
   block      
!$OMP END PARALLEL      
C/C++
#pragma omp parallel [clause ...]  newline       
                     if (scalar_expression)       
                     private (list)       
                     shared (list)       
                     default (shared | none)       
                     firstprivate (list)       
                     reduction (operator: list)       
                     copyin (list)       
                     num_threads (integer-expression)      
   structured_block      

注意:

  • 當線程遇到一個PARALLEL指令,它建立一組線程并成為主要者。主要者也屬于這組線程,并在組内的線程号為0
  • 從這個并行區域開始,代碼被複制并被所有線程執行
  • 并行區域結束時有個隐藏的關卡,隻有主要線程能在此之後繼續執行
  • 并行區域内的任何線程終止都會終止所有的線程。工作不能繼續,直到這點被消除定義。

有多少線程?

  • 并行區域内的線程數量是由以下因素決定的,按優先級排序:
    1.  IF 子句的值
    2.  NUM_THREADS 子句的設定
    3. 使用 omp_set_num_threads() 庫函數
    4. OMP_NUM_THREADS 環境變量
    5. 預設實作-一般是一個計算機的CPU數量,也可能是動态的(參考下節).
  • 線程編号從0 (主線程) to N-1

動态線程:

  • 用 omp_get_dynamic() 庫函數檢測動态線程是否被啟用.
  • 如果支援動态線程,下面兩個方法可以啟用動态線程:
    1. omp_set_dynamic() 庫例程
    2. 設定 OMP_DYNAMIC 環境變量為TRUE

嵌套并行區域:

  • 使用 omp_get_nested()  庫函數檢測嵌套并行區域是否被啟用.
  • 如果支援嵌套并行區域,可以用下面兩個方法啟用:
    1. omp_set_nested() 庫例程
    2. 設定OMP_NESTED 環境變量為TRUE
  • 如果不支援,嵌套并行區域預設将生成一個由單個線程組成的新組。

子句:

  • IF 子句:如果存在,值必須為 .TRUE. (Fortran) 或者非零(C/C++) 以使能建立一組線程. 否則,此區域将被主線程串行執行.
  • 在Data Scope Attribute Clauses 章節,将詳細讨論剩下的子句.

限定:

  • 一個并行區域必須是一個結構塊,不能跨越多個程式或者代碼檔案
  • 進入或者離開一個并行區域的分支都是非法的
  • 隻允許一個IF子句
  • 隻允許一個NUM_THREADS子句

Example: Parallel Region

  • "Hello World" 程式
    • 每一個線程都執行了并行區域的全部代碼
    • OpenMP 庫例程用來獲得線程辨別與總線程數量
Fortran - Parallel Region Example
       PROGRAM HELLO      
       INTEGER NTHREADS, TID, OMP_GET_NUM_THREADS,      
     +   OMP_GET_THREAD_NUM      
C     Fork a team of threads with each thread having a private TID variable      
!$OMP PARALLEL PRIVATE(TID)      
C     Obtain and print thread id      
      TID = OMP_GET_THREAD_NUM()      
      PRINT *, 'Hello World from thread = ', TID      
C     Only master thread does this      
      IF (TID .EQ. 0) THEN      
        NTHREADS = OMP_GET_NUM_THREADS()      
        PRINT *, 'Number of threads = ', NTHREADS      
      END IF      
C     All threads join master thread and disband      
!$OMP END PARALLEL      
       END      

· 

C / C++ - Parallel Region Example
#include <omp.h>      
main ()  {      
int nthreads, tid;      
/* Fork a team of threads with each thread having a private tid variable */      
#pragma omp parallel private(tid)      
  {      
  /* Obtain and print thread id */      
  tid = omp_get_thread_num();      
  printf("Hello World from thread = %d/n", tid);      
  /* Only master thread does this */      
  if (tid == 0)       
    {      
    nthreads = omp_get_num_threads();      
    printf("Number of threads = %d/n", nthreads);      
    }      
  }  /* All threads join master thread and terminate */      
}      

繼續閱讀