OpenMP API概述
OpenMP由三部分組成:
- 編譯指令(19)
- 運行時庫程序(32)
- 環境變量(9)
后來的API包含同樣的三個組件,只是三者的數量都有所增加。
編譯器指令
OpenMP編譯器指令用於各種目的:
- 產生平行區域
- 在線程之間划分代碼塊
- 在線程之間分配循環迭代
- 序列化代碼段
- 線程之間的工作同步
格式如下
#pragma omp <directive> [clause[[,] clause] ...]
通用規則:
- 區分大小寫
- 指令遵循編譯指令的C/C++規則
- 每個指令只能指定一個指令名
- 每個指令最多使用一個后續語句,該語句必須是結構化塊
- 通過在指令行末尾用反斜杠(“\”)轉義換行符,可以在后續行上“繼續”長指令行
並行區域構造:
並行區域是將由多個線程執行的代碼塊。這是基本的OpenMP並行構造。
1 #pragma omp parallel [clause ...] newline 2 if (scalar_expression) 3 private (list) 4 shared (list) 5 default(shared | none) 6 firstprivate (list) 7 reduction (operator:list) 8 copyin (list) 9 num_threads (integer-expression) 10 11 12 structured_block
暫時先解釋以下num_threads語句(其它見另外一篇博客,有點多)
這里的線程數是多少呢?決定線程數的因素有多個,它們的優先級如下:
- if語句的值
- 設置num_threads語句
- 使用的omp_set_num_threads() 庫函數
- 設置的OMP_NUM_THREADS 環境變量
注意:生成的線程編號為0~N,其中0是主線程(master thread)的編號
指令(directive)
共11個
- atomic 內存位置將會原子更新(Specifies that a memory location that will be updated atomically.)
- barrier 線程在此等待,直到所有的線程都運行到此barrier。用來同步所有線程。
- critical 其后的代碼塊為臨界區,任意時刻只能被一個線程運行。
- flush 所有線程對所有共享對象具有相同的內存視圖(view of memory)
- for 用在for循環之前,把for循環並行化由多個線程執行。循環變量只能是整型
- master 指定由主線程來運行接下來的程序。
- ordered 指定在接下來的代碼塊中,被並行化的 for循環將依序運行(sequential loop)
- parallel 代表接下來的代碼塊將被多個線程並行各執行一遍。
- sections 將接下來的代碼塊包含將被並行執行的section塊。
- single 之后的程序將只會在一個線程(未必是主線程)中被執行,不會被並行執行。
- threadprivate 指定一個變量是線程局部存儲(thread local storage)
從句(clause)
共13個
- copyin 讓threadprivate的變量的值和主線程的值相同。
- copyprivate 不同線程中的變量在所有線程中共享。
- default Specifies the behavior of unscoped variables in a parallel region.
- firstprivate 對於線程局部存儲的變量,其初值是進入並行區之前的值。
- if 判斷條件,可用來決定是否要並行化。
- lastprivate 在一個循環並行執行結束后,指定變量的值為循環體在順序最后一次執行時獲取的值,或者#pragma sections在中,按文本順序最后一個section中執行獲取的值。
- nowait 忽略barrier的同步等待。
- num_threads 設置線程數量的數量。默認值為當前計算機硬件支持的最大並發數。一般就是CPU的內核數目。超線程被操作系統視為獨立的CPU內核。
- ordered 使用於 for,可以在將循環並行化的時候,將程序中有標記 directive ordered 的部分依序運行。
- private 指定變量為線程局部存儲。
- reduction Specifies that one or more variables that are private to each thread are the subject of a reduction operation at the end of the parallel region.
- schedule 設置for循環的並行化方法;有 dynamic、guided、runtime、static 四種方法。shared 指定變量為所有線程共享。
- schedule(static, chunk_size) 把chunk_size數目的循環體的執行,靜態依序指定給各線程。
- schedule(dynamic, chunk_size) 把循環體的執行按照chunk_size(缺省值為1)分為若干組(即chunk),每個等待的線程獲得當前一組去執行,執行完后重新等待分配新的組。
- schedule(guided, chunk_size) 把循環體的執行分組,分配給等待執行的線程。最初的組中的循環體執行數目較大,然后逐漸按指數方式下降到chunk_size。
- schedule(runtime) 循環的並行化方式不在編譯時靜態確定,而是推遲到程序執行時動態地根據環境變量OMP_SCHEDULE 來決定要使用的方法。
- shared 指定變量為所有線程共享。
OpenmMP的庫函數(Run-Time Library Routines)
共22個:
1.void omp_set_num_threads(int _Num_threads);
在后續並行區域設置線程數,此調用只影響調用線程所遇到的同一級或內部嵌套級別的后續並行區域.說明:此函數只能在串行代碼部分調用.
2.int omp_get_num_threads(void);
返回當前線程數目.說明:如果在串行代碼中調用此函數,返回值為1.
3.int omp_get_max_threads(void);
如果在程序中此處遇到未使用 num_threads() 子句指定的活動並行區域,則返回程序的最大可用線程數量.說明:可以在串行或並行區域調用,通常這個最大數量由omp_set_num_threads()或OMP_NUM_THREADS環境變量決定.
4.int omp_get_thread_num(void);
返回當前線程id.id從1開始順序編號,主線程id是0.
5.int omp_get_num_procs(void);
返回程序可用的處理器數.
6.void omp_set_dynamic(int _Dynamic_threads);
啟用或禁用可用線程數的動態調整.(缺省情況下啟用動態調整.)此調用只影響調用線程所遇到的同一級或內部嵌套級別的后續並行區域.如果 _Dynamic_threads 的值為非零值,啟用動態調整;否則,禁用動態調整.
7.int omp_get_dynamic(void);
確定在程序中此處是否啟用了動態線程調整.啟用了動態線程調整時返回非零值;否則,返回零值.
8.int omp_in_parallel(void);
確定線程是否在並行區域的動態范圍內執行.如果在活動並行區域的動態范圍內調用,則返回非零值;否則,返回零值.活動並行區域是指 IF 子句求值為 TRUE 的並行區域.
9.void omp_set_nested(int _Nested);
啟用或禁用嵌套並行操作.此調用只影響調用線程所遇到的同一級或內部嵌套級別的后續並行區域._Nested 的值為非零值時啟用嵌套並行操作;否則,禁用嵌套並行操作.缺省情況下,禁用嵌套並行操作.
10.int omp_get_nested(void);
確定在程序中此處是否啟用了嵌套並行操作.啟用嵌套並行操作時返回非零值;否則,返回零值.
互斥鎖操作 嵌套鎖操作 功能
11.void omp_init_lock(omp_lock_t * _Lock); 12. void omp_init_nest_lock(omp_nest_lock_t * _Lock);
初始化一個(嵌套)互斥鎖.
13.void omp_destroy_lock(omp_lock_t * _Lock); 14.void omp_destroy_nest_lock(omp_nest_lock_t * _Lock);
結束一個(嵌套)互斥鎖的使用並釋放內存.
15.void omp_set_lock(omp_lock_t * _Lock); 16.void omp_set_nest_lock(omp_nest_lock_t * _Lock);
獲得一個(嵌套)互斥鎖.
17.void omp_unset_lock(omp_lock_t * _Lock); 18.void omp_unset_nest_lock(omp_nest_lock_t * _Lock);
釋放一個(嵌套)互斥鎖.
19.int omp_test_lock(omp_lock_t * _Lock); 20.int omp_test_nest_lock(omp_nest_lock_t * _Lock);
試圖獲得一個(嵌套)互斥鎖,並在成功時放回真(true),失敗是返回假(false).
21.double omp_get_wtime(void);
獲取wall clock time,返回一個double的數,表示從過去的某一時刻經歷的時間,一般用於成對出現,進行時間比較. 此函數得到的時間是相對於線程的,也就是每一個線程都有自己的時間.
22.double omp_get_wtick(void);
得到clock ticks的秒數.
環境變量(Environment Variables)
1、OMP_SCHEDULE
僅適用於DO,PARALLEL DO(Fortran)和 (C / C ++)指令並行,它們的schedule子句設置為RUNTIME。此變量的值確定如何在處理器上調度循環的迭代。例如:
1 export OMP_SCHEDULE="guided, 4" 2 export OMP_SCHEDULE="dynamic"
2、OMP_NUM_THREADS
設置執行期間要使用的最大線程數。例如:
export OMP_NUM_THREADS=8
3、OMP_DYNAMIC
啟用或禁用動態調整可用於執行並行區域的線程數。有效值為TRUE或FALSE。例如
export OMP_DYNAMIC=TRUE
4、OMP_PROC_BIND
啟用或禁用綁定到處理器的線程。有效值為TRUE或FALSE。例如:
export OMP_PROC_BIND=TRUE
5、OMP_NESTED
啟用或禁用嵌套並行性。有效值為TRUE或FALSE。例如:
export OMP_NESTED=TRUE
6、OMP_STACKSIZE
控制創建(非主)線程的堆棧大小。例如:
1 export OMP_STACKSIZE=2000500B 2 export OMP_STACKSIZE="3000 k " 3 export OMP_STACKSIZE=10M 4 export OMP_STACKSIZE=" 10 M " 5 export OMP_STACKSIZE="20 m " 6 export OMP_STACKSIZE=" 1G" 7 export OMP_STACKSIZE=20000
7、OMP_WAIT_POLICY
提供有關等待線程的所需行為的OpenMP實現的提示。兼容的OpenMP實現可能會也可能不會遵守環境變量的設置。有效值為ACTIVE和PASSIVE。ACTIVE指定等待線程應該主動處於活動狀態,即在等待時消耗處理器周期。PASSIVE指定等待線程應該主要是被動的,即在等待時不消耗處理器周期。ACTIVE和PASSIVE行為的細節是實現定義的。例子:
1 export OMP_WAIT_POLICY=ACTIVE 2 export OMP_WAIT_POLICY=active 3 export OMP_WAIT_POLICY=PASSIVE 4 export OMP_WAIT_POLICY=passive
8、OMP_MAX_ACTIVE_LEVELS
控制嵌套活動並行區域的最大數量。此環境變量的值必須是非負整數。如果請求的OMP_MAX_ACTIVE_LEVELS值大於實現可以支持的嵌套活動並行級別的最大數量,或者該值不是非負整數,則程序的行為是實現定義的。例:
export OMP_MAX_ACTIVE_LEVELS=2
9、OMP_THREAD_LIMIT
設置要用於整個OpenMP程序的OpenMP線程數。此環境變量的值必須是正整數。如果請求的OMP_THREAD_LIMIT值大於實現可以支持的線程數,或者該值不是正整數,則程序的行為是實現定義的。例:
export OMP_THREAD_LIMIT=8
對這些指令詳細的解釋及應用,可見這篇博客
參考鏈接:
