之前對於多執行緒和 OpenMP 的平行化已經做了些簡單的介紹,有興趣的可以回頭參考《簡易的程式平行化方法-OpenMP(一)》。而由於 Heresy 最近看了些資料,也做了些測試,所以主要可能想來講最近學的一些語法吧~
首先,在 Heresy 的認知裡,一般會用到 OpenMP 的部分分為三類:
而 function 的部份是獨立呼叫的,其實在一般的情況下,似乎不大會用到。而 directive 和 clause 的用法,大致上應該是:
#pragma omp directive [clause]
的形式。像之前 #pragma omp parallel for,實際上 parallel 和 for 都是 directive;所以語法實際上可以拆開成 #pragma omp parallel 和 #pragma omp for 兩行。也就是
#pragma omp parallel for
for( int i = 0; i < 10; ++ i )
Test( i );
實際上是
#pragma omp parallel
{
#pragma omp for
for( int i = 0; i < 10; ++ i )
Test( i );
}
所形成的。
而 OpenMP 的 directive 列表如下:
atomic | 記憶體位址將會自動更新。這個指令的目的在於避免變數被同時修改而造成計算結果錯誤。 Specifies that a memory location that will be updated atomically. |
barrier | 等待,直到所有的執行緒都執行到 barrier。用來同步化。 Synchronizes all threads in a team; all threads pause at the barrier, until all threads execute the barrier. |
critical | 強制接下來的程式一次只會被一個執行緒執行。 Specifies that code is only executed on one thread at a time. |
flush | Specifies that all threads have the same view of memory for all shared objects. |
for | 用在 for 迴圈之前,會將迴圈平行化處理。(註:迴圈的 index 只能是 int) Causes the work done in a for loop inside a parallel region to be divided among threads. |
master | 指定由主執行緒來執行接下來的程式。 Specifies that only the master thread should execute a section of the program. |
ordered | 指定接下來被程式,在被平行化的 for 迴圈將依序的執行。 Specifies that code under a parallelized for loop should be executed like a sequential loop. |
parallel | 代表接下來的程式將被平行化。 Defines a parallel region, which is code that will be executed by multiple threads in parallel. |
sections | 將接下來的 section 平行化處理。 Identifies code sections to be divided among all threads. |
single | 之後的程式將只會在一個執行緒執行,不會被平行化。 Lets you specify that a section of code should be executed on a single thread, not necessarily the master thread. |
threadprivate | Specifies that a variable is private to a thread. |
其中,要拿來平行化,是使用 parallel、sections、for 這三項;而要指定使用單一執行緒,則是特過 master、single、crigical 這三項。barrier 則是拿來控制執行緒同步用的;ordered 是用來設定平行化的執行順序。atomic、flush、threadprivate 則應該都是用來控制變數的。
而 clause 的部份,則有下列 13 個:
|
讓 threadprivate 的變數的值和主執行緒的值相同。 |
|
將不同執行緒中的變數共用。 |
default |
設定平行化時對變數處理方式的預設值。 |
讓每個執行緒中,都有一份變數的複本,以免互相干擾;而起始值則會是開始平行化之前的變數值。 |
|
if |
判斷條件,可以用來決定是否要平行化。 |
|
讓每個執行緒中,都有一份變數的複本,以免互相干擾;而在所有平行化的執行緒都結束後,會把最後的值,寫回主執行緒。 |
忽略 barrier(等待)。 |
|
設定平行化時執行緒的數量。 |
|
ordered |
使用於 for,可以在將迴圈平行化的時候,將程式中有標記 directive ordered 的部份依序執行。 |
private |
讓每個執行緒中,都有一份變數的複本,以免互相干擾。 |
對各執行緒的變數,直行指定的運算元來合併寫回主執行緒。 |
|
設定 for 迴圈的平行化方法;有 dynamic、guided、runtime、static 四種方法。 |
|
|
將變數設定為各執行緒共用(應該算是相對於 private 的)。 |
而在 clause 的中,copyin、copyprivate、default、shared、private、firstprivate、lastprivate、reduction 這 8 項,都是用來控制變數在平行化時的處理方法的。ordered 和 schedule 是控制平行化時的執行順序分配方法;num_threads、if 則比較像是控制執行緒的設定。
而在 Function 的部份,MSDN 列了二十來個 function;
雖然一般可能用不到,但是在測試的時候,為了驗正執行的順序、多執行緒的關係,有時候必須要知道線在是由哪個執行緒在跑的~這時候,可以透過 omp_get_thread_num() 這個函式,來取得目前執行緒的編號。
註:
- 雖然 VisualStudio 2005 Express 也有 OpenMP 的選項,但是實際上並沒有附上 OpenMP 的函式庫,所以理論上是不能用的;不過如果能找到 Standard 或 Professional 版的檔案放進去,也是可以運作的!
- 神奇的是…原則上如果沒有用到 OpenMP 的 Function,而只是用 directive 和 clause 的話,應該是可以不用 #include <omp.h> 才對;但是在 Express 中,不加入 #include <omp.h> 可以正確的編譯、執行,而 Professional 版卻只能正確的編譯,而無法正確的執行(dll 起始錯誤)。
參考資料:
- OpenMP并行程序设计(一):http://blog.csdn.net/drzhouweiming/archive/2006/08/28/1131537.aspx
OpenMP并行程序设计(二):http://blog.csdn.net/drzhouweiming/archive/2006/09/04/1175848.aspx - MSDN 的 OpenMP:http://msdn2.microsoft.com/en-us/library/tt15eb9t.aspx