3. ランタイム ライブラリの関数
このセクションでは、OpenMP C および C++ ランタイム ライブラリ関数について説明します。 ヘッダー <omp.h> は、2 つの型、並列実行環境の制御とクエリに使用できる複数の関数、およびデータへのアクセスを同期するために使用で るロック関数を宣言します。
型 omp_lock_t
は、ロックが使用可能であること、またはスレッドがロックを所有していることを表すことができるオブジェクト型です。 これらのロックは、単純なロックと呼ばれます。
型 omp_nest_lock_t
は、ロックが使用可能であること、またはロックを所有しているスレッドの ID と入れ子数の両方を表すことができるオブジェクト型です (以下で説明します)。 これらのロックは、入れ子可能なロックと呼ばれます。
ライブラリ関数は、"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
関数が 0 を返すプログラムの一部から呼び出された場合に、上記で説明した効果を持ちます。 omp_in_parallel
関数が 0 以外の値を返すプログラムの一部から呼び出された場合、この関数の動作は未定義になります。
この呼び出しは、 OMP_NUM_THREADS
環境変数よりも優先されます。 omp_set_num_threads
を呼び出すか、OMP_NUM_THREADS
環境変数を設定することによって確立されるスレッドの数の既定値は、num_threads
句を指定することによって、1 つの parallel
ディレクティブで明示的にオーバーライドできます。
詳細については、「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 以外の値を返します。それ以外の場合は 0 を返します。 形式は次のとおりです。
#include <omp.h>
int omp_in_parallel(void);
この関数は、並列で実行されている領域内から、シリアル化された入れ子になった領域を含めて、0 以外の値を返します。
3.1.7 omp_set_dynamic 関数
omp_set_dynamic
関数は、並列領域の実行に使用できるスレッド数の動的調整を有効または無効にします。 形式は次のとおりです。
#include <omp.h>
void omp_set_dynamic(int dynamic_threads);
dynamic_threads が 0 以外の値に評価される場合、システムリソースを最適に使用するために、実行時の環境によって、今後の並列領域の実行に使用されるスレッドの数が自動的に調整されることがあります。 その結果、ユーザーによって指定されたスレッドの数がスレッドの最大数になります。 並列領域を実行しているチーム内のスレッドの数は、その並列領域の存続期間中は固定され、omp_get_num_threads
関数によって報告されます。
dynamic_threads が 0 に評価される場合、動的調整は無効になります。
この関数は、omp_in_parallel
関数が 0 を返すプログラムの一部から呼び出された場合に、上記で説明した効果を持ちます。 omp_in_parallel
関数が 0 以外の値を返すプログラムの一部から呼び出された場合、この関数の動作は未定義になります。
omp_set_dynamic
への呼び出しは、OMP_DYNAMIC
環境変数よりも優先されます。
スレッドの動的調整の既定値は、実装によって定義されます。 結果として、特定のスレッド数に依存するユーザーコードを正しく実行するには、動的スレッドを明示的に無効にする必要があります。 実装では、スレッドの数を動的に調整する機能を提供する必要はありませんが、すべてのプラットフォーム間での移植性をサポートするインターフェイスを提供する必要があります。
Microsoft 固有の仕様
omp_get_dynamic
と omp_set_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 以外の値を返し、それ以外の場合は 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);
nested が 0 に評価された場合、入れ子になった並列処理は無効になり (これが既定)、入れ子になった並列領域は現在のスレッドによってシリアル化および実行されます。 そうしなければ、入れ子になった並列処理が有効になります。入れ子になった並列領域では、入れ子になったチームを形成するために追加のスレッドがデプロイされる可能性があります。
この関数は、omp_in_parallel
関数が 0 を返すプログラムの一部から呼び出された場合に、上記で説明した効果を持ちます。 omp_in_parallel
関数が 0 以外の値を返すプログラムの一部から呼び出された場合、この関数の動作は未定義になります。
この呼び出しは、 OMP_NESTED
環境変数よりも優先されます。
入れ子になった並列処理が有効になっている場合、入れ子になった並列領域の実行に使用されるスレッドの数は、実装で定義されます。 その結果、OpenMP 準拠の実装では、入れ子になった並列処理が有効になっている場合でも、入れ子になった並列領域をシリアル化できます。
クロスリファレンス
3.1.10 omp_get_nested 関数
omp_get_nested
関数は、入れ子になった並列処理が有効な場合は 0 以外の値を返し、無効になっている場合は 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 関数
これらの関数は、ロックを初期化する唯一の手段を提供します。 各関数は、今後の呼び出しで使用するために、パラメーター lock に関連付けられたロックを初期化します。 形式は次のとおりです。
#include <omp.h>
void omp_init_lock(omp_lock_t *lock);
void omp_init_nest_lock(omp_nest_lock_t *lock);
初期状態はロック解除されます (つまり、ロックを所有するスレッドはありません)。 入れ子可能なロックの場合、最初の入れ子の数は 0 です。 既に初期化されているロック変数を使用して、これらのルーチンのいずれかを呼び出す操作は推奨されません。
3.2.2 omp_destroy_lock 関数と omp_destroy_nest_lock 関数
これらの関数は、ロック変数ロックを指す 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
関数は入れ子数をデクリメントし、関数を実行しているスレッドをロックの所有権から解放します (結果のカウントが 0 の場合)。
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_lock
および omp_set_nest_lock
と同じ方法でロックの設定を試みます。
単純ロックの場合、omp_test_lock
関数は、ロックが正常に設定されているときは 0 以外の値を返します。それ以外の場合は 0 を返します。
入れ子可能なロックの場合、omp_test_nest_lock
関数は、ロックが正常に設定されているときは新しい入れ子数を返します。それ以外の場合は 0 を返します。
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);