OpenMPでomp sections
を使用する場合、スレッドはsections内のブロックに分散されますか、それとも各スレッドは各セクションに割り当てられますか?
nthreads == 3
の場合:
#pragma omp sections
{
#pragma omp section
{
printf ("id = %d, \n", omp_get_thread_num());
}
#pragma omp section
{
printf ("id = %d, \n", omp_get_thread_num());
}
}
出力:
id=1
id=1
しかし、次のコードを実行すると:
#pragma omp sections
{
#pragma omp section
{
printf ("id = %d, \n", omp_get_thread_num());
}
#pragma omp section
{
printf ("id = %d, \n", omp_get_thread_num());
}
}
#pragma omp sections
{
#pragma omp section
{
printf ("id = %d, \n", omp_get_thread_num());
}
#pragma omp section
{
printf ("id = %d, \n", omp_get_thread_num());
}
}
出力:
id=1
id=1
id=2
id=2
これらの出力から、OpenMPのセクションの概念が理解できません。
OPによってポストされたコードは、並行して実行されることはありませんparallel
キーワードが表示されないため。 OPが0とは異なるIDを取得したという事実は、おそらく彼のコードが並列ディレクティブに埋め込まれていることを示しています。しかし、これは彼の投稿から明らかではなく、初心者を混乱させるかもしれません。
最小限の賢明な例は次のとおりです(OPが最初に投稿した例の場合)。
#pragma omp parallel sections
{
#pragma omp section
{
printf ("id = %d, \n", omp_get_thread_num());
}
#pragma omp section
{
printf ("id = %d, \n", omp_get_thread_num());
}
}
私のマシンでは、これは印刷します
id = 0,
id = 1,
2つのセクションが異なるスレッドによって実行されていることを示しています。
ただし、このコードは2つのスレッドよりも多くの並列処理を抽出できないことに注意してください。より多くのスレッドで実行される場合、他のスレッドは実行する作業がなく、ただアイドル状態になります。
並列セクションの考え方は、さまざまな(内部)セクションを並列に実行できるというヒントをコンパイラーに与えることです。次に例を示します。
#pragma omp parallel sections
{
#pragma omp section
{
/* Executes in thread 1 */
}
#pragma omp section
{
/* Executes in thread 2 */
}
#pragma omp section
{
/* Executes in thread 3 */
}
/* ... */
}
これはコンパイラーへのヒントであり、発生することは保証されていませんが、発生するはずです。あなたの出力は期待されるものの一種です。スレッドID 1とスレッド2で#sectionsが実行されていることを示しています。最初に実行されるスレッドがわからないため、出力順序は非決定的です。
最初の行を
#pragma ompセクション
に
#pragma omp parallelセクション
「parallel」ディレクティブは、2つのセクションが2つのスレッドに割り当てられるようにします。次に、次の出力id = 0、id = 1を受け取ります。
parallel
キーワードがありません。 parallel
キーワードは、openmpの並列実行をトリガーします。
OpenMP標準3.1 のセクション2.5.2(エンファシスマイニング)によると:
セクションコンストラクトは、非反復的なワークシェアリングコンストラクトです。このコンストラクトには、チーム内のスレッド間で分散され、実行されるの構造化ブロックのセットが含まれます。各構造化ブロックは、暗黙的なタスクのコンテキストでチーム内でスレッドの1つによって1回実行されますです。
...
セクション構造内の各構造化ブロックの前には、おそらく最初のブロックを除き、セクションディレクティブが先行します。最初のブロックの場合、先行するセクションディレクティブはオプションです。 チーム内のスレッド間で構造化ブロックをスケジュールする方法は、実装定義です。 nowait句が指定されていない限り、セクション構造の最後に暗黙の障壁があります。
したがって、これらのルールをあなたのケースに適用すると、次のように主張できます。
sections
ディレクティブで識別される異なる構造化ブロックは、1つのスレッドで1回実行です。つまり、スレッドの数に関係なく、常に4つのプリントがありますsections
のブロックが(非決定的な順序で)実行されますbefore 2番目のsections
のブロックも(非決定的な順序で実行されます) )。これは、ワークシェアリング構造の最後に暗黙の障壁があるためです。したがって、出力は、スケジューラがチーム内のスレッドに異なるブロックを割り当てることを決定した方法によるものです。
出力行に情報を追加し、セクションを追加すると便利です(スレッド数がある場合)。
#pragma omp parallel sections
{
#pragma omp section
{
printf ("section 1 id = %d, \n", omp_get_thread_num());
}
#pragma omp section
{
printf ("section 2 id = %d, \n", omp_get_thread_num());
}
#pragma omp section
{
printf ("section 3 id = %d, \n", omp_get_thread_num());
}
}
次に、次のようなより興味深い出力が得られます。
section 1 id = 4,
section 3 id = 3,
section 2 id = 1,
使用可能なスレッドによって、セクションがどのような順序で実行されるかを示しています。
'nowait'は、スレッドがexitセクションまで待機する必要がないことをコンパイラに通知することに注意してください。 Fortranでは、「nowait」はループまたはセクションの最後にあるため、これがより明確になります。