說明:這部分內容比較基礎,主要是分析幾個容易混淆的OpenMP函數,加以理解。
(1)並列區域數量的確定:
在這裡,先回顧一下OpenMP的parallel並列區域線程數量的確定,對於一個並列區域,有一個team的線程去執行,那麼該分配多少個線程去執行呢?
OpenMP的遇到parallel指令後建立的線程team的數量由如下過程決定:
1. if子句的結果
2. num_threads的設定
3. omp_set_num_threads()庫函數的設定
4. OMP_NUM_THREADS環境變數的設定
5. 編譯器預設實現(一般而言,預設實現的是匯流排程數等於處理器的核心數)
(http://blog.csdn.net/gengshenghong/article/details/6956878查看更多資訊)
2、3、4優先順序依次降低的,也就是前面的設定可以覆蓋後面的設定,當然也是相對而言,num_threads子句只會影響當前的並列區域,而omp_set_num_threads對OMP_NUM_THREADS環境變數的覆蓋是在整個程式運行期間全域的。
(2)幾個容易混淆的OpenMP函數
1. omp_get_thread_num
擷取線程的num,即ID。這裡的ID是OpenMP的team內的ID,在OpenMP中,一個team內的線程的ID是俺順序排列的,0、1、2...
說明:此函數在並列區域外或者並列區域內都可以調用。在並列區域外,擷取的是master線程的ID,即為0。在並列區域內,每次執行到此函數,擷取的是當前執行線程的ID。
此函數比較容易理解,主要是不要和下面的omp_get_num_threads記混淆了。
2. omp_get_num_threads/omp_set_num_threads
設定/擷取線程數量,此set函數是上面確定遇到parallel指令後建立team的線程的決定方式之一,用於覆蓋OMP_NUM_THREADS環境變數的設定。
說明:儘管從函數名上看,它們是一對set/get函數,但是要區分它們的含義,set之後馬上get,其值不一定等於set的結果,而且大部分情況都是不相等的!
首先來理解omp_set_num_threads():
作用上來說,我們知道它是用於覆蓋環境變數OMP_NUM_THREDS的設定的,使用上來說,要注意的是,omp_set_num_threads只能用於並列區域之外,如果用於並列區域之內,在Debug下運行時會輸出“User Error 1001: omp_set_num_threads should only be called in serial regions”到控制台,如果是Release模式不會輸出,理論上應該是被忽略了。總之,在串列代碼區調用omp_set_num_threads來設定線程數量。
然後分析omp_get_num_threads():
用於擷取當前線程組(team)的線程數量,如果不在並行區調用,返回1.
這句話就清楚了描述了get的作用了,擷取的是當前線程組的線程數量,所以一般會在並列區域調用,其返回的是實際的parallel地區內由上面幾大因素決定之後的實際的啟動並執行線程數量,並不是set的值,所以也很容易理解,在串列區調用它會返回1(所以一般也不會在串列區去調用)。
總結:omp_set_num_threads在串列地區調用才會有效,omp_get_num_threads擷取當前線程組的線程數量,一般在並列區域調用,在串列地區調用返回為1。兩個函數沒有本質上的數量關係!
3. omp_get_max_threads:
從函數名看,貌似是“擷取最大的線程數量”,是的,那麼這個“最大的線程數量"的具體含義呢?下面是OpenMP文檔上的一段話:
The omp_get_max_threads routine returns an upper bound on the number of threads that could be used to form a new team if a parallel region without a num_threads clause were encountered after execution returns
from this routine。
很清楚的說明了,這個”最大數量“是指在不使用num_threads的情況下,OpenMP形成一個新的team能建立的最大線程數量。從這裡要理解到:這個最大數量,是能確定的,與其在並列區域調用,還是在串列地區調用是無關的,因為它是返回OpenMP當前環境下去建立一個”新的“team能建立的可能的最大數量。簡單的理解,其實,這個值就是由以下三者確定:omp_set_num_threads、OMP_NUM_THREADS、編譯器預設實現。
注意:omp_get_max_threads可以在串列或並列區域內調用,而且其結果是一樣的(在其間不調用omp_set_num_threads的情況下),如果有效調用(串列區調用)了omp_set_num_threads,會改變接下來調用omp_get_max_threads的值。另外,omp_get_max_threads的傳回值可能會小於omp_set_num_threads。
4. 執行個體:
下面的例子是使用上面幾個函數的例子,根據結果可以分析出上面提到的一些內容:
#include <omp.h>int main(int argc, _TCHAR* argv[]) {printf("ID: %d, Max threads: %d, Num threads: %d \n",omp_get_thread_num(), omp_get_max_threads(), omp_get_num_threads());omp_set_num_threads(5);printf("ID: %d, Max threads: %d, Num threads: %d \n",omp_get_thread_num(), omp_get_max_threads(), omp_get_num_threads());#pragma omp parallel num_threads(5){// omp_set_num_threads(6);// Do not call it in parallel regionprintf("ID: %d, Max threads: %d, Num threads: %d \n",omp_get_thread_num(), omp_get_max_threads(), omp_get_num_threads());}printf("ID: %d, Max threads: %d, Num threads: %d \n",omp_get_thread_num(), omp_get_max_threads(), omp_get_num_threads());omp_set_num_threads(6);printf("ID: %d, Max threads: %d, Num threads: %d \n",omp_get_thread_num(), omp_get_max_threads(), omp_get_num_threads());return 0; }