OpenMPのは、共有メモリ並列システム、C、C ++およびFortranなど、サポートされているプログラミング言語のためのマルチスレッドプログラミング方式です。OpenMPのは、並列アルゴリズムの抽象化のレベルは、マシンのマルチコアCPUの設計上の並列プログラムのために特に適して記載されて提供されます。プログラムコンパイラプラグマの命令は、OpenMPを用いた並列プログラミングは困難と複雑さを低減、自動並列処理プログラムを追加しました。コンパイラは、OpenMPをサポートしていない場合は、プログラムが正常な(シリアル)プログラムに退化します。すでにプログラムでのOpenMPディレクティブは、コンパイラの正常な動作には影響しません。
有効OpenMPのは、VS、OpenMPのを建て、多くの主流のコンパイラ環境では非常に簡単です。プロジェクトを右 - >プロパティ - >構成プロパティ - > C / C ++ - >言語 - > OpenMPサポート、 "はい" ボタンを選択します。
OpenMPの実行モード
フォーク加入実行モードを使用してのOpenMP。並列コンピューティングの必要性は、並列タスクを実行するスレッドの分岐数を導出する際に最初に、唯一のメインスレッドがあります。並列コードの実行が完了すると、スレッドの分岐は、結合、および別メインスレッドへの制御フロー。
典型的な概略フォークジョイン実行モデルを次のように
OpenMPのプログラミングモデルは、指令誘導を並列化するために、コンパイラによって導かれた基礎を、スレッドために、彼らは指導、API関数セットと環境変数をコンパイルしている並列プログラミング制御を実現することができる3つの要素があります。
指導をコンパイルします
ます。#pragma ompのコンパイラガイダンスは、次のような特定の機能命令、フォーマットに戻って起動するコマンドの#pragma ompのディレクティブ[句[句] ...] 。次のように共通の特徴の説明は、次のとおりです。
- パラレル:ブロック構造を使用する前に、このコードは、並列実行複数のスレッドによって表され;
用:前ループ文の中で使用するには、タスクの共有を実現するために、並列実行の複数のスレッドに割り当てられた周期計算タスクを示し、プログラマが各サイクルの間に相関せず、それらのデータていることを確認しなければならない。
平行用:結合と平行するための命令は、前のループのために使用される、スレッドの並列複数で実行されるループ本体のコードを表します。それはまた、タスク生成二つの並列時間ドメインの機能を共有有し、
セクション:前のコードセグメントを並列に実行することができるとともに、構造的な複数のブロックは、タスク共有ステートメントコードセグメントは、各々に並列に実行することができる達成します指示部は、(セクションとセクションの間の区別に注意)示し;
平行セクション:セクションと二つの平行な結合文、同様の並列のため、
単一:技術と並行して、単一スレッドの期間を示すコードが実行され、
クリティカル。コード領域のクリティカルセクションを使用する前に、一つだけのスレッドのOpenMPが入ることを確実にするために、
フラッシュを:各画像OpenMPスレッド内のデータの整合性を保証する;
バリア:すべてのスレッドが実行されるまで障壁がダウン継続するときにコード同期内平行でスレッド、バリアにスレッドの実行を停止して待機するため、
アトミック:ためデータ操作がアトミック実行する必要が指定し、
マスター:コードのセクションを指定し、メインスレッドによって実行されます。
THREADPRIVATE:後述するように1つ以上の変数は、特別なスレッドです指定し、スレッド固有のプライベートの区別。
対応するOpenMPの句:
プライベート:一つ以上の変数が各スレッドに独自のプライベートコピーを持って指定します。
FIRSTPRIVATE:指定一つ以上の変数は、各スレッドの独自のプライベートコピーを持っており、プライベート変数は、フィールドまたは並列に入力しますタスク共有ドメインは、同じ変数の値を初期値として、メインスレッドに継承される。
LASTPRIVATE:並列処理の後、メインスレッドにコピーされ、同じ名前の変数またはスレッドプライベート変数の複数の値を指定するために使用され;、スレッドのセクションのタスクの共有または最後のスレッドをコピーするための責任がある
減少はプライベートであることを1つまたは複数の変数を指定し、これらの変数は、並列処理後の結果を縮小操作を実行するために指定:同じ名前の変数のメインスレッドに戻す;
NOWAIT:同時スレッドは、他のガイダンスは、暗黙のバリア同期を命令無視でき指摘;
NUM_THREADS:並列当スレッドの数、
スケジュール:タイプを共有するタスクの指定されたタスクの割り当てスケジュール;
共有は:一つまたは指定複数の変数は、複数のスレッド間で変数を共有し、
注文した:のために ;シリアル巡回順序で実行される指定されたコード・セグメント内の指定されたタスクを共有する必要性のために
COPYPRIVATE同じ変数は当並列に他のスレッドにブロードキャストされ、指定されたスレッド固有の変数を持つ単一の命令;
COPYIN:変数THREADPRIVATEのタイプを指定します私たちは、同じ名前の変数のメインスレッドで初期化する必要があります。
デフォルト:並列可変ドメインの使用を指定するために使用され、デフォルトでは共有されています。
API関数
上記のコンパイラガイダンスコマンドに加えて、OpenMPのも同時スレッドの特定の動作を制御するためのAPI関数のセットを提供し、ここではいくつかの一般的な機能やOpenMPのAPIの説明です:
環境変数
OpenMPのは、行動OpenMPプログラムは、一般的に、環境変数を使用し、これらの環境変数によって制御することができ、いくつかの環境変数を定義します。
- OMP_SCHEDULE:ループの並列化のためのスケジューリングのために、値はラウンドロビンスケジューリングタイプである。
OMP_NUM_THREADS:ドメインの並列内のスレッドの数;
OMP_DYNAMIC:動的セットを並列技術を許可するかどうかを決定するために変数の値を設定することによりスレッドの数;
OMP_NESTEDは:パラレルネストかどうかを示します。
平行の使用の簡単な例
パラレルガイダンスはバックブレースを維持するためのコードが一緒に並列に実行されるように、並列のドメインを作成するためのコマンド:
-
#include<iostream>
-
#include"omp.h"
-
using namespace std;
-
void main()
-
{
-
#pragma omp parallel
-
{
-
cout << "Test" << endl;
-
}
-
system("pause");
-
}
上記の手順に以下の出力を行います。
プログラムは、4つの並列スレッドが一度実行された後、スレッドの4つの手続きデフォルト数を文を説明し、4「test」を出力し、スレッドの数はまた、句NUM_THREADS明示的に制御することによって作成することができます。
-
#include<iostream>
-
#include"omp.h"
-
using namespace std;
-
void main()
-
{
-
#pragma omp parallel num_threads(6)
-
{
-
cout << "Test" << endl;
-
}
-
system("pause");
-
}
次の出力をコンパイルして実行します。
プログラムは、明示的並列文のブロックが6回実行され、6つのスレッドを定義します。各スレッドは、スレッドが出力文字「テスト」は、別のスレッドに直接出力文字「テスト」の行を変更するには時間がなかった後でいる、独立して実行されるので、2行目は空白行です。
使用のための並列の簡単な例
複数のスレッドが同じタスク、および実際の使用価値を実行しているように、単に、パラレルドメインを持っていたパラレルガイダンスコマンドを使用します。パラレルドメインの並列を生成するため、および走行速度が算出されるように、複数のスレッド間でのタスクの分布を算出します。システムはデフォルトのスレッド数もスレッドNUM_THREADS句の数を指定するために使用することができます割り当てるせることができます。
-
#include<iostream>
-
#include"omp.h"
-
using namespace std;
-
void main()
-
{
-
#pragma omp parallel for num_threads(6)
-
for (int i = 0; i < 12; i++)
-
{
-
printf("OpenMP Test, 线程编号为: %d\n", omp_get_thread_num());
-
}
-
system("pause");
-
}
出力を実行します。
プログラムが上糸6、12回の繰り返しの量を指定し、出力は、各スレッドが反復の12/6 = 2倍の量を割り当てることがわかります。
OpenMPの効率向上と効率が異なるスレッドの数を比較します
-
#include<iostream>
-
#include"omp.h"
-
using namespace std;
-
void test()
-
{
-
for (int i = 0; i < 80000; i++)
-
{
-
}
-
}
-
void main()
-
{
-
float startTime = omp_get_wtime();
-
//指定2个线程
-
#pragma omp parallel for num_threads(2)
-
for (int i = 0; i < 80000; i++)
-
{
-
test();
-
}
-
float endTime = omp_get_wtime();
-
printf("指定 2 个线程,执行时间: %f\n", endTime - startTime);
-
startTime = endTime;
-
//指定4个线程
-
#pragma omp parallel for num_threads(4)
-
for (int i = 0; i < 80000; i++)
-
{
-
test();
-
}
-
endTime = omp_get_wtime();
-
printf("指定 4 个线程,执行时间: %f\n", endTime - startTime);
-
startTime = endTime;
-
//指定8个线程
-
#pragma omp parallel for num_threads(8)
-
for (int i = 0; i < 80000; i++)
-
{
-
test();
-
}
-
endTime = omp_get_wtime();
-
printf("指定 8 个线程,执行时间: %f\n", endTime - startTime);
-
startTime = endTime;
-
//指定12个线程
-
#pragma omp parallel for num_threads(12)
-
for (int i = 0; i < 80000; i++)
-
{
-
test();
-
}
-
endTime = omp_get_wtime();
-
printf("指定 12 个线程,执行时间: %f\n", endTime - startTime);
-
startTime = endTime;
-
//不使用OpenMP
-
for (int i = 0; i < 80000; i++)
-
{
-
test();
-
}
-
endTime = omp_get_wtime();
-
printf("不使用OpenMP多线程,执行时间: %f\n", endTime - startTime);
-
startTime = endTime;
-
system("pause");
-
}
以上程序分别指定了2、4、8、12个线程和不使用OpenMP优化来执行一段垃圾程序,输出如下:
可见,使用OpenMP优化后的程序执行时间是原来的1/4左右,并且并不是线程数使用越多效率越高,一般线程数达到4~8个的时候,不能简单通过提高线程数来进一步提高效率。