3.執行時間程式庫函式
本節描述 OpenMP C 和 C++ 執行時間程式庫函式。 標頭 < omp.h > 會宣告兩種類型、數個可用來控制及查詢平行執行環境的函式,以及用來同步處理資料存取權的鎖定函式。
此類型 omp_lock_t
是一種物件類型,能夠表示鎖定可供使用,或是執行緒擁有鎖定。 這些鎖定稱為 簡單鎖定 。
此類型 omp_nest_lock_t
是一種物件類型,可以代表鎖定可供使用,或是擁有鎖定的執行緒身分識別和 巢狀計數 (如下所述)。 這些鎖定稱為 可巢狀鎖定 。
程式庫函式是具有 「C」 連結的外部函式。
本章的描述分為下列主題:
3.1 執行環境函式
本節所述的函式會影響和監視執行緒、處理器和平行環境:
- omp_set_num_threads
- omp_get_num_threads
- omp_get_max_threads
- omp_get_thread_num
- omp_get_num_procs
- omp_in_parallel
- omp_set_dynamic
- omp_get_dynamic
- omp_set_nested
- omp_get_nested
3.1.1 omp_set_num_threads 函式
函式會 omp_set_num_threads
設定預設的執行緒數目,以用於未指定 num_threads
子句的後續平列區域。 格式如下:
#include <omp.h>
void omp_set_num_threads(int num_threads);
參數 的值num_threads 必須是正整數。 其效果取決於是否啟用執行緒數目的動態調整。 如需有關函式與執行緒動態調整之間 omp_set_num_threads
互動的完整規則集,請參閱 2.3 節。
從函式傳回零的程式部分 omp_in_parallel
呼叫時,此函式具有上述效果。 如果從函式傳回非零值的程式 omp_in_parallel
部分呼叫,則此函式的行為為未定義。
此呼叫的優先順序高於 OMP_NUM_THREADS
環境變數。 藉由呼叫 omp_set_num_threads
或 設定 OMP_NUM_THREADS
環境變數,可以明確覆寫單 parallel
一指示詞上的執行緒數目預設值,方法是指定 num_threads
子句。
如需詳細資訊,請參閱 omp_set_dynamic 。
交叉參考
- omp_set_dynamic 函式
- omp_get_dynamic 函式
- OMP_NUM_THREADS環境變數
- num_threads 子句
3.1.2 omp_get_num_threads 函式
函 omp_get_num_threads
式會傳回目前在小組中執行其呼叫之平列區域的執行緒數目。 格式如下:
#include <omp.h>
int omp_get_num_threads(void);
子句、函 num_threads
omp_set_num_threads
式和 OMP_NUM_THREADS
環境變數可控制小組中的執行緒數目。
如果使用者尚未明確設定執行緒數目,則預設值為實作定義。 此函式會系結至最接近的封入 parallel
指示詞。 如果從程式的序列部分呼叫,或從序列化的巢狀平列區域呼叫,則此函式會傳回 1。
如需詳細資訊,請參閱 omp_set_dynamic 。
交叉參考
3.1.3 omp_get_max_threads 函式
函 omp_get_max_threads
式會傳回一個整數,如果程式碼中的該時間點看到沒有 num_threads
子句的平列區域,則保證至少與用來形成小組的執行緒數目一樣大。 格式如下:
#include <omp.h>
int omp_get_max_threads(void);
下列內容表示 的值下 omp_get_max_threads
限:
threads-used-for-next-team < =
omp_get_max_threads
請注意,如果另一個平列區域使用 num_threads
子句來要求特定數目的執行緒,則不再保留結果 omp_get_max_threads
的下限保證。
函 omp_get_max_threads
式的傳回值可用來針對下一個平列區域中組成之小組中的所有線程動態配置足夠的儲存體。
交叉參考
3.1.4 omp_get_thread_num 函式
函式 omp_get_thread_num
會傳回執行函式之執行緒小組內的執行緒編號。 執行緒編號介於 0 和 omp_get_num_threads()
-1 之間,內含。 小組的主要執行緒為執行緒 0。
格式如下:
#include <omp.h>
int omp_get_thread_num(void);
如果從序欄區域呼叫, omp_get_thread_num
則傳回 0。 如果從序列化的巢狀平列區域內呼叫,此函式會傳回 0。
交叉參考
3.1.5 omp_get_num_procs 函式
函 omp_get_num_procs
式會傳回呼叫函式時程式可用的處理器數目。 格式如下:
#include <omp.h>
int omp_get_num_procs(void);
3.1.6 omp_in_parallel 函式
如果函式是在平行執行之平列區域的動態範圍內呼叫,則會 omp_in_parallel
傳回非零值,否則會傳回 0。 格式如下:
#include <omp.h>
int omp_in_parallel(void);
從平行執行的區域內呼叫時,此函式會傳回非零值,包括序列化的巢狀區域。
3.1.7 omp_set_dynamic 函式
函 omp_set_dynamic
式會啟用或停用平列區域執行可用執行緒數目的動態調整。 格式如下:
#include <omp.h>
void omp_set_dynamic(int dynamic_threads);
如果 dynamic_threads 評估為非零值,則執行時間環境可能會自動調整用於執行即將推出的平列區域的執行緒數目,以充分利用系統資源。 因此,使用者指定的執行緒數目是執行緒計數上限。 執行平列區域的小組中線程數目會針對該平列區域的持續時間維持固定狀態,並由 函式 omp_get_num_threads
報告。
如果 dynamic_threads 評估為 0,則會停用動態調整。
從函式傳回零的程式部分 omp_in_parallel
呼叫時,此函式具有上述效果。 如果從函式傳回非零值的程式 omp_in_parallel
部分呼叫,則此函式的行為為未定義。
對 omp_set_dynamic
的呼叫優先順序高於 OMP_DYNAMIC
環境變數。
執行緒動態調整的預設值是實作定義。 因此,相依于特定數目執行緒以進行正確執行的使用者代碼應該明確停用動態執行緒。 實作不需要提供動態調整執行緒數目的能力,但必須提供介面來支援跨所有平臺的可攜性。
Microsoft 專有
和 omp_set_dynamic
的目前支援 omp_get_dynamic
如下所示:
的 omp_set_dynamic
輸入參數不會影響執行緒原則,也不會變更執行緒數目。 omp_get_num_threads
如果已設定,則一律會傳回使用者定義的數位,或預設執行緒編號。 在目前的 Microsoft 實作中, omp_set_dynamic(0)
關閉動態執行緒,讓現有的執行緒集可以重複使用於下列平列區域。 omp_set_dynamic(1)
藉由捨棄現有的執行緒集,並為即將推出的平列區域建立新集合,以開啟動態執行緒。 新集中的執行緒數目與舊集合相同,且是以 的 omp_get_num_threads
傳回值為基礎。 因此,為了達到最佳效能,請使用 omp_set_dynamic(0)
重複使用現有的執行緒。
交叉參考
3.1.8 omp_get_dynamic 函式
如果啟用執行緒的動態調整,則函 omp_get_dynamic
式會傳回非零值,否則會傳回 0。 格式如下:
#include <omp.h>
int omp_get_dynamic(void);
如果實作未實作執行緒數目的動態調整,此函式一律會傳回 0。 如需詳細資訊,請參閱 omp_set_dynamic 。
交叉參考
- 如需動態執行緒調整的描述,請參閱 omp_set_dynamic 。
3.1.9 omp_set_nested 函式
函 omp_set_nested
式會啟用或停用巢狀平行處理原則。 格式如下:
#include <omp.h>
void omp_set_nested(int nested);
如果 巢狀 評估為 0,則會停用巢狀平行處理原則,這是預設值,且巢狀平列區域會由目前線程序列化和執行。 否則,會啟用巢狀平行處理原則,而巢狀的平列區域可能會部署其他執行緒以形成巢狀小組。
從函式傳回零的程式部分 omp_in_parallel
呼叫時,此函式具有上述效果。 如果從函式傳回非零值的程式 omp_in_parallel
部分呼叫,則此函式的行為為未定義。
此呼叫的優先順序高於 OMP_NESTED
環境變數。
啟用巢狀平行處理原則時,用來執行巢狀平列區域的執行緒數目是實作定義的。 因此,即使已啟用巢狀平行處理原則,也允許 OpenMP 相容的實作序列化巢狀平列區域。
交叉參考
3.1.10 omp_get_nested 函式
如果已啟用巢狀平行處理原則,則函 omp_get_nested
式會傳回非零值,如果停用則傳回 0。 如需巢狀平行處理原則的詳細資訊,請參閱 omp_set_nested 。 格式如下:
#include <omp.h>
int omp_get_nested(void);
如果實作未實作巢狀平行處理原則,此函式一律會傳回 0。
3.2 鎖定函式
本節所述的函式會操作用於同步處理的鎖定。
針對下列函式,鎖定變數必須具有 類型 omp_lock_t
。 此變數只能透過這些函式存取。 所有鎖定函式都需要具有型別指標的 omp_lock_t
引數。
- omp_init_lock函式 會初始化簡單的鎖定。
- omp_destroy_lock 函式會移除簡單的鎖定。
- omp_set_lock 函式會等到有簡單的鎖定可用為止。
- omp_unset_lock 函式會釋放簡單的鎖定。
- omp_test_lock函式 會測試簡單的鎖定。
針對下列函式,鎖定變數必須具有 類型 omp_nest_lock_t
。 此變數只能透過這些函式存取。 所有可巢狀鎖定函式都需要具有型別指標的 omp_nest_lock_t
引數。
- omp_init_nest_lock函式 會初始化可巢狀鎖定。
- omp_destroy_nest_lock函式 會移除可巢狀鎖定。
- omp_set_nest_lock 函式會等到有巢狀鎖定可用為止。
- omp_unset_nest_lock 函式會釋放可巢狀鎖定。
- omp_test_nest_lock函式 會測試可巢狀鎖定。
OpenMP 鎖定函式會以一律讀取和更新鎖定變數目前值的方式存取鎖定變數。 因此,OpenMP 程式不需要包含明確的 flush
指示詞,以確保鎖定變數的值在不同的執行緒之間是一致的。 (可能需要 flush
指示詞讓其他變數的值保持一致。
3.2.1 omp_init_lock和omp_init_nest_lock函式
這些函式提供初始化鎖定的唯一方法。 每個函式都會初始化與參數 鎖定相關聯的鎖定 ,以用於即將來臨的呼叫。 格式如下:
#include <omp.h>
void omp_init_lock(omp_lock_t *lock);
void omp_init_nest_lock(omp_nest_lock_t *lock);
初始狀態已解除鎖定(也就是沒有線程擁有鎖定)。 對於可巢狀鎖定,初始巢狀計數為零。 使用已初始化的鎖定變數呼叫這其中一個常式並不符合規範。
3.2.2 omp_destroy_lock和omp_destroy_nest_lock函式
這些函式可確保指向鎖定變數 鎖定 未初始化。 格式如下:
#include <omp.h>
void omp_destroy_lock(omp_lock_t *lock);
void omp_destroy_nest_lock(omp_nest_lock_t *lock);
使用未初始化或解除鎖定的鎖定變數呼叫這其中一個常式是不合規的。
3.2.3 omp_set_lock 和 omp_set_nest_lock 函式
每個函式都會封鎖執行函式的執行緒,直到指定的鎖定可用為止,然後設定鎖定。 如果鎖定,即可使用簡單的鎖定。 如果巢狀鎖定已解除鎖定,或已由執行函式的執行緒擁有,可以使用巢狀鎖定。 格式如下:
#include <omp.h>
void omp_set_lock(omp_lock_t *lock);
void omp_set_nest_lock(omp_nest_lock_t *lock);
對於簡單的鎖定,函式的 omp_set_lock
引數必須指向初始化的鎖定變數。 鎖定的擁有權會授與執行函式的執行緒。
對於可巢狀鎖定,函式的 omp_set_nest_lock
引數必須指向初始化的鎖定變數。 巢狀計數會遞增,並授與執行緒或保留鎖定的擁有權。
3.2.4 omp_unset_lock和omp_unset_nest_lock函式
這些函式提供釋放鎖定擁有權的方法。 格式如下:
#include <omp.h>
void omp_unset_lock(omp_lock_t *lock);
void omp_unset_nest_lock(omp_nest_lock_t *lock);
每個函式的引數都必須指向執行函式之執行緒所擁有的初始化鎖定變數。 如果執行緒未擁有該鎖定,則行為未定義。
針對簡單的鎖定,函 omp_unset_lock
式會從鎖定的擁有權釋放執行函式的執行緒。
對於可巢狀鎖定,函 omp_unset_nest_lock
式會遞減巢狀計數,並在產生的計數為零時,從鎖定擁有權釋放執行函式的執行緒。
3.2.5 omp_test_lock和omp_test_nest_lock函式
這些函式會嘗試設定鎖定,但不會封鎖執行緒的執行。 格式如下:
#include <omp.h>
int omp_test_lock(omp_lock_t *lock);
int omp_test_nest_lock(omp_nest_lock_t *lock);
引數必須指向初始化的鎖定變數。 這些函式會嘗試以 與 和 omp_set_nest_lock
相同的方式 omp_set_lock
設定鎖定,不同之處在于它們不會封鎖執行緒的執行。
對於簡單的鎖定,如果成功設定鎖定,函 omp_test_lock
式會傳回非零值,否則會傳回零。
對於可巢狀鎖定,如果鎖定成功設定,函 omp_test_nest_lock
式會傳回新的巢狀計數,否則會傳回零。
3.3 計時常式
本節所述的函式支援可攜式時鐘計時器:
- omp_get_wtime 函式會傳回經過的時鐘時間。
- omp_get_wtick 函式會傳回連續時鐘刻度之間的秒數。
3.3.1 omp_get_wtime 函式
函 omp_get_wtime
式會傳回雙精確度浮點數,等於經過的時鐘時間,以秒為單位,因為有些「過去的時間」。 實際的「過去時間」是任意的,但保證不會在應用程式程式執行期間變更。 格式如下:
#include <omp.h>
double omp_get_wtime(void);
預期函式將用來測量經過的時間,如下列範例所示:
double start;
double end;
start = omp_get_wtime();
... work to be timed ...
end = omp_get_wtime();
printf_s("Work took %f sec. time.\n", end-start);
傳回的時間是「每一線程時間」,這表示在參與應用程式的所有線程之間不需要全域一致。
3.3.2 omp_get_wtick 函式
函 omp_get_wtick
式會傳回雙精確度浮點數,等於連續時鐘刻度之間的秒數。 格式如下:
#include <omp.h>
double omp_get_wtick(void);