
OpenMPテクノロジーの知識を継続し、いくつかの機能と新しいディレクティブを検討しましょう。
OpenMPには多くのヘルパー関数があります。 これらを使用するには、ヘッダーファイル<omp.h>を含めることを忘れないでください。
ランタイム関数
これらの関数を使用すると、OpenMP環境のさまざまなパラメーターを照会および設定できます。
- omp_get_num_procs-コンピューター内のコンピューティングノード(プロセッサー/コア)の数を返します。
- omp_in_parallel- スレッドが現在並列領域を実行しているかどうかを確認できます。
- omp_get_num_threads-現在のスレッドグループに含まれるスレッドの数を返します。
- omp_set_num_thread-現在実行中のスレッドを満たす次の並列領域を実行するスレッドの数を設定します。 関数はリソースの割り当てに役立ちます。 たとえば、4つのコアを持つプロセッサでサウンドとビデオを同時に処理する場合、サウンド用に1つのストリーム、ビデオ処理用に3つのストリームを作成できます。
- omp_get_max_threads-次の並列領域で使用するスレッドの最大数を返します。
- omp_set_nested-ネストされた並行性を有効または無効にします。 ネストされた並列処理が許可されている場合、並列領域の記述が検出された各スレッドは、実行用の新しいスレッドグループを生成し、そのスレッドのメイングループになります。
- omp_get_nested-ネストされた並行性が許可されているかどうかを返す
関数名がomp_set_で始まる場合、並列領域の外部でのみ呼び出すことができます。 他のすべての関数は、並列領域内と並列領域外の両方で使用できます。
同期/ロック機能
OpenMPでは、特定のタイプの同期を許可するディレクティブがあるため、これらの関数を使用せずに並列コードを構築できます。 ただし、場合によっては、これらの機能は便利であり、必要なこともあります。
OpenMPには、シンプルとネストの2種類のロックがあります。 添付ファイルの接尾辞は「nest」です。 ロックは、未初期化、ロック、ロック解除の3つの状態のいずれかになります。
- omp_init_lock / omp_init_nest_lock-omp_lock_t / omp_nest_lock_t型の変数の初期化。 InitializeCriticalSectionに類似しています。
- omp_destroy_lock / omp_destroy_nest_lock-omp_lock_t / omp_nest_lock_t型の変数を解放します。 DeleteCriticalSectionに類似。
- omp_set_lock / omp_set_nest_lock-1つのスレッドがロックを設定し、残りのスレッドは、この関数を呼び出したスレッドがomp_unset_lock()関数を使用してロックを解除するまで待機します。 アナログEnterCriticalSection。
- omp_unset_lock / omp_unset_nest_lock-ロックを解除します。 LeaveCriticalSectionのアナログ。
- omp_test_lock / omp_test_nest_lock-キャッスルをロックする非ブロック試行。 この関数は、指定されたロックをキャプチャしようとします。 これが成功した場合、単純なロックの場合、関数は1を返します。ロックをキャプチャできなかった場合、0が返されますTryEnterCriticalSectionの類似物。
同じスレッドであっても、単純ロック(omp_lock_t)を複数回設定することはできません。 ネストされたロック(omp_nest_lock_t)は単純なものと同じです。ただし、スレッドが既にそれに属するネストされたロックを設定しようとすると、ブロックされません。
次に、説明した機能を使用するコードの例を示します。 順番に作成されるすべてのスレッドには、「作業開始」および「作業終了」メッセージが表示されます。 1つのスレッドからのこれら2つのメッセージの間に、閉じたセクションへの入力に失敗したときに表示される他のスレッドからのメッセージが存在する場合があります。
omp_lock_tロック; int n; omp_init_lock(&ロック); #pragma omp parallel private(n) { n = omp_get_thread_num(); while(!omp_test_lock(&lock)) { printf( "Wait ...、thread%d \ n"、n); 睡眠(3); } printf( "作業開始、スレッド%d \ n"、n); 睡眠(5); //作業... printf( "作業終了、スレッド%d \ n"、n); omp_unset_lock(&ロック); } omp_destroy_lock(&ロック);
4つのコアを持つマシンでは、次の出力を取得できます。
作業を開始、スレッド0
待って...、スレッド1
待って...、スレッド2
待って...、スレッド3
待って...、スレッド2
待って...、スレッド3
待って...、スレッド1
作業終了、スレッド0
作業を開始、スレッド2
待って...、スレッド3
待って...、スレッド1
待って...、スレッド3
待って...、スレッド1
作業終了、スレッド2
作業を開始、スレッド3
待って...、スレッド1
待って...、スレッド1
作業終了、スレッド3
作業を開始、スレッド1
作業終了、スレッド1
タイマー機能
- omp_get_wtime-過去のある時点から経過した、呼び出し元のストリームの天文時間(2倍の実数)を秒単位で返します。 プログラムのセクションがこの関数の呼び出しに囲まれている場合、戻り値の違いはこのセクションの動作時間を示します。
- omp_get_wtick()-呼び出しスレッドのタイマーの解像度(秒単位)、つまりタイマーの精度を返します。
これについては、関数の紹介を終了し、いくつかの新しいディレクティブを検討します。 これらのディレクティブは、並列領域を作成するためのオプションと呼ばれます。
if(条件)
条件による並列領域の実行。 複数のスレッドの作成は、特定の条件が満たされた場合にのみ実行されます。 条件が満たされない場合、コードはシーケンシャルモードで実行されます。
使用例:
voidテスト(bool x) { #pragma omp parallel if(x) if(omp_in_parallel()) { #pragma omp single printf_s( "%dスレッドで並列化\ n"、 omp_get_num_threads()); } 他に { printf_s( "シングルスレッド\ n"); } } int _tmain(int argc、_TCHAR * argv []) { テスト(false); テスト(true); 0を返します。 }
仕事の結果:
シングルスレッド 4つのスレッドで並列化
num_threads
並列領域を実行するスレッドの数の明示的な設定。 デフォルトでは、omp_set_num_threads()関数を使用して設定された最後の値が選択されます。
上記の例を次のように変更した場合:
... #pragma omp parallel if(x)num_threads(3) ...
次の出力が得られます。
シングルスレッド 3つのスレッドで並列化
Parallel Notesの次号では、続きます...