web-dev-qa-db-ja.com

OpenMPのSECTIONSディレクティブはどのように機能しますか?

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のセクションの概念が理解できません。

39
kar

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つのスレッドよりも多くの並列処理を抽出できないことに注意してください。より多くのスレッドで実行される場合、他のスレッドは実行する作業がなく、ただアイドル状態になります。

92
Spock

並列セクションの考え方は、さまざまな(内部)セクションを並列に実行できるというヒントをコンパイラーに与えることです。次に例を示します。

#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が実行されていることを示しています。最初に実行されるスレッドがわからないため、出力順序は非決定的です。

26
wump

最初の行を

#pragma ompセクション

#pragma omp parallelセクション

「parallel」ディレクティブは、2つのセクションが2つのスレッドに割り当てられるようにします。次に、次の出力id = 0、id = 1を受け取ります。

12
user2752126

parallelキーワードがありません。 parallelキーワードは、openmpの並列実行をトリガーします。

9
Charles Chow

OpenMP標準3.1 のセクション2.5.2(エンファシスマイニング)によると:

セクションコンストラクトは、非反復的なワークシェアリングコンストラクトです。このコンストラクトには、チーム内のスレッド間で分散され、実行されるの構造化ブロックのセットが含まれます。各構造化ブロックは、暗黙的なタスクのコンテキストでチーム内でスレッドの1つによって1回実行されますです。

...

セクション構造内の各構造化ブロックの前には、おそらく最初のブロックを除き、セクションディレクティブが先行します。最初のブロックの場合、先行するセクションディレクティブはオプションです。 チーム内のスレッド間で構造化ブロックをスケジュールする方法は、実装定義です。 nowait句が指定されていない限り、セクション構造の最後に暗黙の障壁があります。

したがって、これらのルールをあなたのケースに適用すると、次のように主張できます。

  1. sectionsディレクティブで識別される異なる構造化ブロックは、1つのスレッドで1回実行です。つまり、スレッドの数に関係なく、常に4つのプリントがあります
  2. 最初のsectionsのブロックが(非決定的な順序で)実行されますbefore 2番目のsectionsのブロックも(非決定的な順序で実行されます) )。これは、ワークシェアリング構造の最後に暗黙の障壁があるためです。
  3. スケジューリングは実装定義であるため、特定のセクションに割り当てられたスレッドを制御することはできません。

したがって、出力は、スケジューラがチーム内のスレッドに異なるブロックを割り当てることを決定した方法によるものです。

4
Massimiliano

出力行に情報を追加し、セクションを追加すると便利です(スレッド数がある場合)。

#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,

使用可能なスレッドによって、セクションがどのような順序で実行されるかを示しています。

2
RungeKutta4

'nowait'は、スレッドがexitセクションまで待機する必要がないことをコンパイラに通知することに注意してください。 Fortranでは、「nowait」はループまたはセクションの最後にあるため、これがより明確になります。

0
pburka