OpenMP ディレクティブ

OpenMP API 内で使用されるディレクティブへのリンクを提供します。

Visual C++ では、次の OpenMP ディレクティブがサポートされています。

並列作業共有の場合:

ディレクティブ 説明
parallel 並列領域を定義します。これは、複数のスレッドによって並列に実行されるコードです。
for 並列領域内の for ループで実行された作業をスレッド間で分割します。
sections すべてのスレッド間で分割するコード セクションを識別します。
single コードのセクションを、必ずしもメインスレッドではなく、1 つのスレッドで実行することを指定できます。

メインスレッドと同期の場合:

ディレクティブ 説明
master メイン スレッドのみがプログラムのセクションを実行することを指定します。
critical コードが一度に 1 つのスレッドでのみ実行される場合に指定します。
barrier チーム内のすべてのスレッドを同期します。すべてのスレッドがバリアを実行するまで、すべてのスレッドがバリアで一時停止します。
atomic アトミックに更新されるメモリの場所を指定します。
flush すべてのスレッドが、すべての共有オブジェクトに対して同じメモリ ビューを持つことを指定します。
ordered 並列化された for ループの下のコードをシーケンシャル ループのように実行する必要がある場合に指定します。

データ環境:

ディレクティブ 説明
threadprivate 変数がスレッドに対してプライベートである場合に指定します。

atomic

アトミックに更新されるメモリの場所を指定します。

#pragma omp atomic
   expression

パラメーター

式 (expression)
lvalue を持つステートメントで、そのメモリロケーションを複数回の書き込みから保護します。

解説

atomic ディレクティブでは句はサポートされません。

詳細は、2.6.4 アトミック コンストラクトを参照してください。

// omp_atomic.cpp
// compile with: /openmp
#include <stdio.h>
#include <omp.h>

#define MAX 10

int main() {
   int count = 0;
   #pragma omp parallel num_threads(MAX)
   {
      #pragma omp atomic
      count++;
   }
   printf_s("Number of threads: %d\n", count);
}
Number of threads: 10

barrier

チーム内のすべてのスレッドを同期します。すべてのスレッドがバリアを実行するまで、すべてのスレッドがバリアで一時停止します。

#pragma omp barrier

解説

barrier ディレクティブでは句はサポートされません。

詳細は、2.6.3 バリア ディレクティブを参照してください。

barrier の使用例については、マスターを参照してください。

critical

コードが一度に 1 つのスレッドでのみ実行される場合に指定します。

#pragma omp critical [(name)]
{
   code_block
}

パラメーター

name
(省略可能)重要なコードを識別する名前。 名前はかっこで囲む必要があります。

解説

critical ディレクティブでは句はサポートされません。

詳細は、2.6.2 クリティカル コンストラクトを参照してください。

// omp_critical.cpp
// compile with: /openmp
#include <omp.h>
#include <stdio.h>
#include <stdlib.h>

#define SIZE 10

int main()
{
    int i;
    int max;
    int a[SIZE];

    for (i = 0; i < SIZE; i++)
    {
        a[i] = rand();
        printf_s("%d\n", a[i]);
    }

    max = a[0];
    #pragma omp parallel for num_threads(4)
        for (i = 1; i < SIZE; i++)
        {
            if (a[i] > max)
            {
                #pragma omp critical
                {
                    // compare a[i] and max again because max
                    // could have been changed by another thread after
                    // the comparison outside the critical section
                    if (a[i] > max)
                        max = a[i];
                }
            }
        }

    printf_s("max = %d\n", max);
}
41
18467
6334
26500
19169
15724
11478
29358
26962
24464
max = 29358

flush

すべてのスレッドが、すべての共有オブジェクトに対して同じメモリ ビューを持つことを指定します。

#pragma omp flush [(var)]

パラメーター

var
(省略可能) 同期するオブジェクトを表す変数のコンマ区切りのリスト。 var を指定しない場合、すべてのメモリがフラッシュされます。

解説

flush ディレクティブでは句はサポートされません。

詳細は、2.6.5 フラッシュ ディレクティブを参照してください。

// omp_flush.cpp
// compile with: /openmp
#include <stdio.h>
#include <omp.h>

void read(int *data) {
   printf_s("read data\n");
   *data = 1;
}

void process(int *data) {
   printf_s("process data\n");
   (*data)++;
}

int main() {
   int data;
   int flag;

   flag = 0;

   #pragma omp parallel sections num_threads(2)
   {
      #pragma omp section
      {
         printf_s("Thread %d: ", omp_get_thread_num( ));
         read(&data);
         #pragma omp flush(data)
         flag = 1;
         #pragma omp flush(flag)
         // Do more work.
      }

      #pragma omp section
      {
         while (!flag) {
            #pragma omp flush(flag)
         }
         #pragma omp flush(data)

         printf_s("Thread %d: ", omp_get_thread_num( ));
         process(&data);
         printf_s("data = %d\n", data);
      }
   }
}
Thread 0: read data
Thread 1: process data
data = 2

for

並列領域内の for ループで実行された作業をスレッド間で分割します。

#pragma omp [parallel] for [clauses]
   for_statement

パラメーター


(省略可能) 0 個以上の句については、注釈セクションを参照してください。

for_statement
for ループ。 for ループのユーザー コードでインデックス変数が変更されると、未定義の動作が発生します。

解説

for ディレクティブは、次の句をサポートしています。

parallel も指定されている場合は、parallel または for ディレクティブで受け入れられる任意の句 clauses を指定できます (ただし、nowait を除く)。

詳細については、「2.4.1 for コンストラクト」を参照してください。

// omp_for.cpp
// compile with: /openmp
#include <stdio.h>
#include <math.h>
#include <omp.h>

#define NUM_THREADS 4
#define NUM_START 1
#define NUM_END 10

int main() {
   int i, nRet = 0, nSum = 0, nStart = NUM_START, nEnd = NUM_END;
   int nThreads = 0, nTmp = nStart + nEnd;
   unsigned uTmp = (unsigned((abs(nStart - nEnd) + 1)) *
                               unsigned(abs(nTmp))) / 2;
   int nSumCalc = uTmp;

   if (nTmp < 0)
      nSumCalc = -nSumCalc;

   omp_set_num_threads(NUM_THREADS);

   #pragma omp parallel default(none) private(i) shared(nSum, nThreads, nStart, nEnd)
   {
      #pragma omp master
      nThreads = omp_get_num_threads();

      #pragma omp for
      for (i=nStart; i<=nEnd; ++i) {
            #pragma omp atomic
            nSum += i;
      }
   }

   if  (nThreads == NUM_THREADS) {
      printf_s("%d OpenMP threads were used.\n", NUM_THREADS);
      nRet = 0;
   }
   else {
      printf_s("Expected %d OpenMP threads, but %d were used.\n",
               NUM_THREADS, nThreads);
      nRet = 1;
   }

   if (nSum != nSumCalc) {
      printf_s("The sum of %d through %d should be %d, "
               "but %d was reported!\n",
               NUM_START, NUM_END, nSumCalc, nSum);
      nRet = 1;
   }
   else
      printf_s("The sum of %d through %d is %d\n",
               NUM_START, NUM_END, nSum);
}
4 OpenMP threads were used.
The sum of 1 through 10 is 55

master

メイン スレッドのみがプログラムのセクションを実行することを指定します。

#pragma omp master
{
   code_block
}

解説

master ディレクティブでは句はサポートされません。

詳細は、2.6.1 master コンストラクトを参照してください。

コードのセクションを 1 つのスレッドで実行するように指定するには(必ずしもメインスレッドではない)、代わりに単一のディレクティブを使用します。

// compile with: /openmp
#include <omp.h>
#include <stdio.h>

int main( )
{
    int a[5], i;

    #pragma omp parallel
    {
        // Perform some computation.
        #pragma omp for
        for (i = 0; i < 5; i++)
            a[i] = i * i;

        // Print intermediate results.
        #pragma omp master
            for (i = 0; i < 5; i++)
                printf_s("a[%d] = %d\n", i, a[i]);

        // Wait.
        #pragma omp barrier

        // Continue with the computation.
        #pragma omp for
        for (i = 0; i < 5; i++)
            a[i] += i;
    }
}
a[0] = 0
a[1] = 1
a[2] = 4
a[3] = 9
a[4] = 16

ordered

並列化された for ループの下のコードをシーケンシャル ループのように実行する必要がある場合に指定します。

#pragma omp ordered
   structured-block

解説

ordered ディレクティブは、for または parallel for 構成と ordered 句の動的範囲内になければなりません。

ordered ディレクティブでは句はサポートされません。

詳細は、2.6.6 ordered コンストラクトを参照してください。

// omp_ordered.cpp
// compile with: /openmp
#include <stdio.h>
#include <omp.h>

static float a[1000], b[1000], c[1000];

void test(int first, int last)
{
    #pragma omp for schedule(static) ordered
    for (int i = first; i <= last; ++i) {
        // Do something here.
        if (i % 2)
        {
            #pragma omp ordered
            printf_s("test() iteration %d\n", i);
        }
    }
}

void test2(int iter)
{
    #pragma omp ordered
    printf_s("test2() iteration %d\n", iter);
}

int main( )
{
    int i;
    #pragma omp parallel
    {
        test(1, 8);
        #pragma omp for ordered
        for (i = 0 ; i < 5 ; i++)
            test2(i);
    }
}
test() iteration 1
test() iteration 3
test() iteration 5
test() iteration 7
test2() iteration 0
test2() iteration 1
test2() iteration 2
test2() iteration 3
test2() iteration 4

parallel

並列領域を定義します。これは、複数のスレッドによって並列に実行されるコードです。

#pragma omp parallel [clauses]
{
   code_block
}

パラメーター


(省略可能) 0 個以上の句については、注釈セクションを参照してください。

解説

parallel ディレクティブは、次の句をサポートしています。

parallel は、forsections ディレクティブと共に使用することもできます。

詳細は、2.3 parallel コンストラクトを参照してください。

次のサンプルは、スレッドの数を設定し、並列領域を定義する方法を示しています。 スレッド数は、既定ではコンピューター上の論理プロセッサの数と同じになります。 たとえば、ハイパースレッディングが有効になっている 1 台の物理プロセッサを搭載したマシンでは、2 つの論理プロセッサと 2 つのスレッドがあります。 出力の順序は、コンピューターによって異なる場合があります。

// omp_parallel.cpp
// compile with: /openmp
#include <stdio.h>
#include <omp.h>

int main() {
   #pragma omp parallel num_threads(4)
   {
      int i = omp_get_thread_num();
      printf_s("Hello from thread %d\n", i);
   }
}
Hello from thread 0
Hello from thread 1
Hello from thread 2
Hello from thread 3

セクション

すべてのスレッド間で分割するコード セクションを識別します。

#pragma omp [parallel] sections [clauses]
{
   #pragma omp section
   {
      code_block
   }
}

パラメーター


(省略可能) 0 個以上の句については、注釈セクションを参照してください。

解説

sections ディレクティブには、0 個以上の section ディレクティブを含めることができます。

sections ディレクティブは、次の句をサポートしています。

parallel も指定されている場合は、parallel または sections ディレクティブで受け入れられる任意の句 clauses を指定できます (ただし、nowait を除く)。

詳細は、2.4.2 sections コンストラクトを参照してください。

// omp_sections.cpp
// compile with: /openmp
#include <stdio.h>
#include <omp.h>

int main() {
    #pragma omp parallel sections num_threads(4)
    {
        printf_s("Hello from thread %d\n", omp_get_thread_num());
        #pragma omp section
        printf_s("Hello from thread %d\n", omp_get_thread_num());
    }
}
Hello from thread 0
Hello from thread 0

single

コードのセクションを、必ずしもメインスレッドではなく、1 つのスレッドで実行することを指定できます。

#pragma omp single [clauses]
{
   code_block
}

パラメーター


(省略可能) 0 個以上の句については、注釈セクションを参照してください。

解説

single ディレクティブは、次の句をサポートしています。

詳細は、2.4.3 single コンストラクトを参照してください。

コードのセクションを メイン スレッドでのみ実行するように指定するには、代わりに master ディレクティブを使用します。

// omp_single.cpp
// compile with: /openmp
#include <stdio.h>
#include <omp.h>

int main() {
   #pragma omp parallel num_threads(2)
   {
      #pragma omp single
      // Only a single thread can read the input.
      printf_s("read input\n");

      // Multiple threads in the team compute the results.
      printf_s("compute results\n");

      #pragma omp single
      // Only a single thread can write the output.
      printf_s("write output\n");
    }
}
read input
compute results
compute results
write output

threadprivate

変数がスレッドに対してプライベートである場合に指定します。

#pragma omp threadprivate(var)

パラメーター

var
スレッドに対してプライベートにする変数のコンマ区切りのリスト。 var は、グローバルまたは名前空間スコープの変数またはローカルの静的変数のいずれかである必要があります。

解説

threadprivate ディレクティブでは句はサポートされません。

threadprivate ディレクティブは thread 属性に __declspec キーワードを使用し、__declspec(thread) に関する制限は threadprivate に適用されます。 たとえば、threadprivate 変数は、並列領域によって生成されるスレッド チームの一部であるスレッドだけでなく、プロセスで開始されたスレッドにも存在します。 この実装の詳細に注意してください。場合によっては、threadprivate ユーザー定義型のコンストラクターがより頻繁に呼び出されることに注意してください。

threadprivate はプロセス起動時に静的にロードされる DLL で使用できますが、threadprivate/DELAYLOAD (delay load import) でロードされる DLL のように LoadLibrary でロードされる DLL では使用できません (LoadLibrary も使用される)。

destructible 型の threadprivate 変数は、そのデストラクターが呼ばれることが保証されていません。 次に例を示します。

struct MyType
{
    ~MyType();
};

MyType threaded_var;
#pragma omp threadprivate(threaded_var)
int main()
{
    #pragma omp parallel
    {}
}

ユーザーは並列領域を作成するスレッドが終了するタイミングを制御できません。 プロセスの終了時にそれらのスレッドが存在する場合、そのスレッドにはプロセスの終了が通知されず、終了したスレッド (ここではプライマリ スレッド) 以外のスレッドで threaded_var に対するデストラクターが呼び出されることはありません。 したがって、コードは threadprivate 変数の適切な破棄をカウントしないでください。

詳細は、2.7.1 threadprivate ディレクティブを参照してください。

threadprivate の使用例については、プライベートを参照してください。