動的スケジュールまたは OpenMP タスクで OpenMP 並列を使用できます。どちらも、各反復が完了するまでにかかる時間が異なるケースを並列化するために使用できます。動的にスケジュールされている場合:
#pragma omp parallel
{
Fitter fitter;
fitter.init();
#pragma omp for schedule(dynamic,1)
for (int i = 0; i < numFits; i++)
fitter.fit(..., &results[i]);
}
schedule(dynamic,1)
各スレッドが一度に 1 つの反復を実行し、処理する反復がなくなるまでスレッドがアイドル状態になることはありません。
タスクの場合:
#pragma omp parallel
{
Fitter fitter;
fitter.init();
#pragma omp single
for (int i = 0; i < numFits; i++)
{
#pragma omp task
fitter.fit(..., &results[i]);
}
#pragma omp taskwait
// ^^^ only necessary if more code before the end of the parallel region
}
ここで、スレッドの 1 つは、1000 個の OpenMP タスクを生成する for ループを実行します。OMP タスクはキューに保持され、アイドル スレッドによって処理されます。これは動的 for ループといくらか似た働きをしますが、コード構成の自由度が高くなります (たとえば、タスクを使用して再帰アルゴリズムを並列化できます)。コンストラクトは、保留中のtaskwait
すべてのタスクが完了するまで待機します。これは、並列領域の最後で暗示されるため、実際に必要になるのは、並列領域の終了前にさらにコードが続く場合のみです。
どちらの場合も、への各呼び出しfit()
は別のスレッドで行われます。パラメータの 1 つのセットのフィッティングが他のセットのフィッティングに影響しないことを確認する必要があります。たとえば、それfit()
はスレッドセーフなメソッド/関数です。どちらの場合もfit()
、OpenMP コンストラクトのオーバーヘッドよりもはるかに長い実行時間が必要です。
OpenMP タスクには、OpenMP 3.0 準拠のコンパイラが必要です。これにより、MS VC++ のすべてのバージョン (VS2012 のバージョンも含む) が除外されます。
スレッドごとに初期化されるフィッターのインスタンスを 1 つだけにしたい場合は、フィッター オブジェクトをグローバルにするなど、多少異なるアプローチを取る必要がありますthreadprivate
。
#include <omp.h>
Fitter fitter;
#pragma omp threadprivate(fitter)
...
int main()
{
// Disable dynamic teams
omp_set_dynamic(0);
// Initialise all fitters once per thread
#pragma omp parallel
{
fitter.init();
}
...
#pragma omp parallel
{
#pragma omp for schedule(dynamic,1)
for (int i = 0; i < numFits; i++)
fitter.fit(..., &results[i]);
}
...
return 0;
}
これは、クラスfitter
のグローバル インスタンスです。Fitter
このomp threadprivate
ディレクティブは、スレッドごとのグローバル変数にするなど、スレッド ローカル ストレージに格納するようにコンパイラに指示します。これらは、異なる並列領域間で保持されます。ローカル変数omp threadprivate
にも使用できます。static
これらも、異なる並列領域間で保持されます (ただし、同じ関数内のみ)。
#include <omp.h>
int main()
{
// Disable dynamic teams
omp_set_dynamic(0);
static Fitter fitter; // must be static
#pragma omp threadprivate(fitter)
// Initialise all fitters once per thread
#pragma omp parallel
{
fitter.init();
}
...
#pragma omp parallel
{
#pragma omp for schedule(dynamic,1)
for (int i = 0; i < numFits; i++)
fitter.fit(..., &results[i]);
}
...
return 0;
}
このomp_set_dynamic(0)
呼び出しは動的チームを無効にします。つまり、各並列領域は常に、OMP_NUM_THREADS
環境変数で指定された数のスレッドで実行されます。