OpenMP 節

OpenMP API 内で使用される句へのリンクを提供します。

Visual C++ では、次の OpenMP 句がサポートされています。

一般的な属性:

条項 説明
if ループを並列実行するか順次実行するかを指定します。
num_threads スレッド チーム内のスレッド数を設定します。
注文済み ループ内で ordered ディレクティブを使用する場合は、parallel for ステートメントが必須です。
schedule for ディレクティブに適用されます。
ノーウェイト ディレクティブの暗黙のバリアをオーバーライドします。

データ共有属性:

条件 説明
プライベート 各スレッドに変数の独自のインスタンスが必要であることを指定します。
firstprivate 各スレッドに変数の独自のインスタンスが必要であり、各インスタンスをその変数の値で初期化する (変数が parallel コンストラクトの前に存在するため) ことを指定します。
lastprivate 最後の反復 (for ループ コンストラクト) または最後のセクション (#pragma sections) を実行するスレッドのプライベート バージョンと同じになるように、囲んでいるコンテキストの変数のバージョンを設定することを指定します。
shared 1 つ以上の変数をすべてのスレッド間で共有することを指定します。
default 並列領域内のスコープを持たない変数の動作を指定します。
削減 各スレッドに対してプライベートである 1 つ以上の変数が、並列領域の最後にあるリダクション演算の対象であることを指定します。
コピーイン threadprivate 変数に対して、スレッドがメイン スレッドの値にアクセスできるようにします。
copyprivate 1 つ以上の変数をすべてのスレッド間で共有することを指定します。

コピイン

threadprivate 変数に対して、スレッドがメイン スレッドの値にアクセスできるようにします。

copyin(var)

パラメーター

var
並列コンストラクトの前に存在するので、メイン スレッド内の変数の値で初期化される threadprivate 変数。

解説

copyin は次のディレクティブに適用されます。

詳細については、「2.7.2.7 copyin」を参照してください。

例

「threadprivate」の使用例については、「copyin」を参照してください。

copyprivate

1 つ以上の変数をすべてのスレッド間で共有することを指定します。

copyprivate(var)

パラメーター

var
共有する 1 つ以上の変数。 複数の変数を指定する場合は、変数名をコンマで区切ります。

解説

copyprivate は single ディレクティブに適用されます。

詳細については、「2.7.2.8 copyprivate」を参照してください。

例

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

float x, y, fGlobal = 1.0;
#pragma omp threadprivate(x, y)

float get_float() {
   fGlobal += 0.001;
   return fGlobal;
}

void use_float(float f, int t) {
   printf_s("Value = %f, thread = %d\n", f, t);
}

void CopyPrivate(float a, float b) {
   #pragma omp single copyprivate(a, b, x, y)
   {
      a = get_float();
      b = get_float();
      x = get_float();
      y = get_float();
    }

   use_float(a, omp_get_thread_num());
   use_float(b, omp_get_thread_num());
   use_float(x, omp_get_thread_num());
   use_float(y, omp_get_thread_num());
}

int main() {
   float a = 9.99, b = 123.456;

   printf_s("call CopyPrivate from a single thread\n");
   CopyPrivate(9.99, 123.456);

   printf_s("call CopyPrivate from a parallel region\n");
   #pragma omp parallel
   {
      CopyPrivate(a, b);
   }
}
call CopyPrivate from a single thread
Value = 1.001000, thread = 0
Value = 1.002000, thread = 0
Value = 1.003000, thread = 0
Value = 1.004000, thread = 0
call CopyPrivate from a parallel region
Value = 1.005000, thread = 0
Value = 1.005000, thread = 1
Value = 1.006000, thread = 0
Value = 1.006000, thread = 1
Value = 1.007000, thread = 0
Value = 1.007000, thread = 1
Value = 1.008000, thread = 0
Value = 1.008000, thread = 1

デフォルト

並列領域内のスコープを持たない変数の動作を指定します。

default(shared | none)

解説

shared 句が指定されていない場合に有効な default は、並列領域内の変数を、shared 句で指定されている場合と同様に扱うことを意味します。 none は、並列領域内で使用される変数が、private、shared、reduction、firstprivate、または lastprivate 句でスコープ設定されていない場合に、コンパイラ エラーが発生することを意味します。

default は次のディレクティブに適用されます。

詳細については、「2.7.2.5 default」を参照してください。

例

private の使用例については、default を参照してください。

firstprivate

各スレッドに変数の独自のインスタンスが必要であり、各インスタンスをその変数の値で初期化する (変数が parallel コンストラクトの前に存在するため) ことを指定します。

firstprivate(var)

パラメーター

var
各スレッドでインスタンスを持ち、parallel コンストラクトの前にその変数が存在するため、各インスタンスはその変数の値で初期化されます。 複数の変数を指定する場合は、変数名をコンマで区切ります。

解説

firstprivate は次のディレクティブに適用されます。

詳細については、「2.7.2.2 firstprivate」を参照してください。

例

firstprivate の使用例については、「private」の例を参照してください。

if (OpenMP)

ループを並列実行するか順次実行するかを指定します。

if(expression)

パラメーター

式 (expression)
true (0 以外) に評価された場合に、並列領域内のコードが並列実行される整数式。 式が false (0) に評価された場合、並列領域は (1 つのスレッドによって) 順次実行されます。

解説

if は次のディレクティブに適用されます。

詳細は、2.3 並列構造を参照してください。

例

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

void test(int val)
{
    #pragma omp parallel if (val)
    if (omp_in_parallel())
    {
        #pragma omp single
        printf_s("val = %d, parallelized with %d threads\n",
                 val, omp_get_num_threads());
    }
    else
    {
        printf_s("val = %d, serialized\n", val);
    }
}

int main( )
{
    omp_set_num_threads(2);
    test(0);
    test(2);
}
val = 0, serialized
val = 2, parallelized with 2 threads

lastprivate

最後の反復 (for ループ コンストラクト) または最後のセクション (#pragma sections) を実行するスレッドのプライベート バージョンと同じになるように、囲んでいるコンテキストの変数のバージョンを設定することを指定します。

lastprivate(var)

パラメーター

var
最後の反復 (for ループ コンストラクト) または最後のセクション (#pragma sections) を実行するスレッドのプライベート バージョンと同じになるように設定される変数。

解説

lastprivate は次のディレクティブに適用されます。

詳細については、「2.7.2.3 lastprivate」を参照してください。

例

「スケジュール」を参照すると、「lastprivate」句の使用例があります。

nowait

ディレクティブの暗黙のバリアをオーバーライドします。

nowait

解説

nowait は次のディレクティブに適用されます。

詳細については、「2.4.1 構成に関する項」、「2.4.2 セクションに関連する構成」、「2.4.3 単一の構成」を参照してください。

例

// omp_nowait.cpp
// compile with: /openmp /c
#include <stdio.h>

#define SIZE 5

void test(int *a, int *b, int *c, int size)
{
    int i;
    #pragma omp parallel
    {
        #pragma omp for nowait
        for (i = 0; i < size; i++)
            b[i] = a[i] * a[i];

        #pragma omp for nowait
        for (i = 0; i < size; i++)
            c[i] = a[i]/2;
    }
}

int main( )
{
    int a[SIZE], b[SIZE], c[SIZE];
    int i;

    for (i=0; i<SIZE; i++)
        a[i] = i;

    test(a,b,c, SIZE);

    for (i=0; i<SIZE; i++)
        printf_s("%d, %d, %d\n", a[i], b[i], c[i]);
}
0, 0, 0
1, 1, 0
2, 4, 1
3, 9, 1
4, 16, 2

スレッド数

スレッド チーム内のスレッド数を設定します。

num_threads(num)

パラメーター

num
スレッド数

解説

num_threads 句には、omp_set_num_threads 関数と同じ機能があります。

num_threads は次のディレクティブに適用されます。

詳細は、2.3 並列構造を参照してください。

例

「parallel」を参照して、num_threads 句の使用例を確認してください。

順序付けられた

ループ内で ordered ディレクティブを使用する場合は、parallel for ステートメントが必須です。

ordered

解説

ordered は for ディレクティブに適用されます。

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

例

「ordered」 句の使用例については、「ordered」を参照してください。

非公開

各スレッドに変数の独自のインスタンスが必要であることを指定します。

private(var)

パラメーター

var
各スレッドにインスタンスを持つ変数。

解説

private は次のディレクティブに適用されます。

詳細については、「2.7.2.1 private」を参照してください。

例

// openmp_private.c
// compile with: /openmp
#include <windows.h>
#include <assert.h>
#include <stdio.h>
#include <omp.h>

#define NUM_THREADS 4
#define SLEEP_THREAD 1
#define NUM_LOOPS 2

enum Types {
   ThreadPrivate,
   Private,
   FirstPrivate,
   LastPrivate,
   Shared,
   MAX_TYPES
};

int nSave[NUM_THREADS][MAX_TYPES][NUM_LOOPS] = {{0}};
int nThreadPrivate;

#pragma omp threadprivate(nThreadPrivate)
#pragma warning(disable:4700)

int main() {
   int nPrivate = NUM_THREADS;
   int nFirstPrivate = NUM_THREADS;
   int nLastPrivate = NUM_THREADS;
   int nShared = NUM_THREADS;
   int nRet = 0;
   int i;
   int j;
   int nLoop = 0;

   nThreadPrivate = NUM_THREADS;
   printf_s("These are the variables before entry "
           "into the parallel region.\n");
   printf_s("nThreadPrivate = %d\n", nThreadPrivate);
   printf_s("      nPrivate = %d\n", nPrivate);
   printf_s(" nFirstPrivate = %d\n", nFirstPrivate);
   printf_s("  nLastPrivate = %d\n", nLastPrivate);
   printf_s("       nShared = %d\n\n", nShared);
   omp_set_num_threads(NUM_THREADS);

   #pragma omp parallel copyin(nThreadPrivate) private(nPrivate) shared(nShared) firstprivate(nFirstPrivate)
   {
      #pragma omp for schedule(static) lastprivate(nLastPrivate)
      for (i = 0 ; i < NUM_THREADS ; ++i) {
         for (j = 0 ; j < NUM_LOOPS ; ++j) {
            int nThread = omp_get_thread_num();
            assert(nThread < NUM_THREADS);

            if (nThread == SLEEP_THREAD)
               Sleep(100);
            nSave[nThread][ThreadPrivate][j] = nThreadPrivate;
            nSave[nThread][Private][j] = nPrivate;
            nSave[nThread][Shared][j] = nShared;
            nSave[nThread][FirstPrivate][j] = nFirstPrivate;
            nSave[nThread][LastPrivate][j] = nLastPrivate;
            nThreadPrivate = nThread;
            nPrivate = nThread;
            nShared = nThread;
            nLastPrivate = nThread;
            --nFirstPrivate;
         }
      }
   }

   for (i = 0 ; i < NUM_LOOPS ; ++i) {
      for (j = 0 ; j < NUM_THREADS ; ++j) {
         printf_s("These are the variables at entry of "
                  "loop %d of thread %d.\n", i + 1, j);
         printf_s("nThreadPrivate = %d\n",
                  nSave[j][ThreadPrivate][i]);
         printf_s("      nPrivate = %d\n",
                  nSave[j][Private][i]);
         printf_s(" nFirstPrivate = %d\n",
                  nSave[j][FirstPrivate][i]);
         printf_s("  nLastPrivate = %d\n",
                  nSave[j][LastPrivate][i]);
         printf_s("       nShared = %d\n\n",
                  nSave[j][Shared][i]);
      }
   }

   printf_s("These are the variables after exit from "
            "the parallel region.\n");
   printf_s("nThreadPrivate = %d (The last value in the "
            "main thread)\n", nThreadPrivate);
   printf_s("      nPrivate = %d (The value prior to "
            "entering parallel region)\n", nPrivate);
   printf_s(" nFirstPrivate = %d (The value prior to "
            "entering parallel region)\n", nFirstPrivate);
   printf_s("  nLastPrivate = %d (The value from the "
            "last iteration of the loop)\n", nLastPrivate);
   printf_s("       nShared = %d (The value assigned, "
            "from the delayed thread, %d)\n\n",
            nShared, SLEEP_THREAD);
}
These are the variables before entry into the parallel region.
nThreadPrivate = 4
      nPrivate = 4
nFirstPrivate = 4
  nLastPrivate = 4
       nShared = 4

These are the variables at entry of loop 1 of thread 0.
nThreadPrivate = 4
      nPrivate = 1310720
nFirstPrivate = 4
  nLastPrivate = 1245104
       nShared = 3

These are the variables at entry of loop 1 of thread 1.
nThreadPrivate = 4
      nPrivate = 4488
nFirstPrivate = 4
  nLastPrivate = 19748
       nShared = 0

These are the variables at entry of loop 1 of thread 2.
nThreadPrivate = 4
      nPrivate = -132514848
nFirstPrivate = 4
  nLastPrivate = -513199792
       nShared = 4

These are the variables at entry of loop 1 of thread 3.
nThreadPrivate = 4
      nPrivate = 1206
nFirstPrivate = 4
  nLastPrivate = 1204
       nShared = 2

These are the variables at entry of loop 2 of thread 0.
nThreadPrivate = 0
      nPrivate = 0
nFirstPrivate = 3
  nLastPrivate = 0
       nShared = 0

These are the variables at entry of loop 2 of thread 1.
nThreadPrivate = 1
      nPrivate = 1
nFirstPrivate = 3
  nLastPrivate = 1
       nShared = 1

These are the variables at entry of loop 2 of thread 2.
nThreadPrivate = 2
      nPrivate = 2
nFirstPrivate = 3
  nLastPrivate = 2
       nShared = 2

These are the variables at entry of loop 2 of thread 3.
nThreadPrivate = 3
      nPrivate = 3
nFirstPrivate = 3
  nLastPrivate = 3
       nShared = 3

These are the variables after exit from the parallel region.
nThreadPrivate = 0 (The last value in the main thread)
      nPrivate = 4 (The value prior to entering parallel region)
nFirstPrivate = 4 (The value prior to entering parallel region)
  nLastPrivate = 3 (The value from the last iteration of the loop)
       nShared = 1 (The value assigned, from the delayed thread, 1)

削減

各スレッドに対してプライベートである 1 つ以上の変数が、並列領域の最後にあるリダクション演算の対象であることを指定します。

reduction(operation:var)

パラメーター

操作
並列領域の最後にある変数 var に対して実行する演算の演算子。

var
スカラー リダクションの実行対象となる 1 つ以上の変数。 複数の変数を指定する場合は、変数名をコンマで区切ります。

解説

reduction は次のディレクティブに適用されます。

詳細については、「2.7.2.6 reduction」を参照してください。

例

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

#define NUM_THREADS 4
#define SUM_START   1
#define SUM_END     10
#define FUNC_RETS   {1, 1, 1, 1, 1}

int bRets[5] = FUNC_RETS;
int nSumCalc = ((SUM_START + SUM_END) * (SUM_END - SUM_START + 1)) / 2;

int func1( ) {return bRets[0];}
int func2( ) {return bRets[1];}
int func3( ) {return bRets[2];}
int func4( ) {return bRets[3];}
int func5( ) {return bRets[4];}

int main( )
{
    int nRet = 0,
        nCount = 0,
        nSum = 0,
        i,
        bSucceed = 1;

    omp_set_num_threads(NUM_THREADS);

    #pragma omp parallel reduction(+ : nCount)
    {
        nCount += 1;

        #pragma omp for reduction(+ : nSum)
        for (i = SUM_START ; i <= SUM_END ; ++i)
            nSum += i;

        #pragma omp sections reduction(&& : bSucceed)
        {
            #pragma omp section
            {
                bSucceed = bSucceed && func1( );
            }

            #pragma omp section
            {
                bSucceed = bSucceed && func2( );
            }

            #pragma omp section
            {
                bSucceed = bSucceed && func3( );
            }

            #pragma omp section
            {
                bSucceed = bSucceed && func4( );
            }

            #pragma omp section
            {
                bSucceed = bSucceed && func5( );
            }
        }
    }

    printf_s("The parallel section was executed %d times "
             "in parallel.\n", nCount);
    printf_s("The sum of the consecutive integers from "
             "%d to %d, is %d\n", 1, 10, nSum);

    if (bSucceed)
        printf_s("All of the functions, func1 through "
                 "func5 succeeded!\n");
    else
        printf_s("One or more of the functions, func1 "
                 "through func5 failed!\n");

    if (nCount != NUM_THREADS)
    {
        printf_s("ERROR: For %d threads, %d were counted!\n",
                 NUM_THREADS, nCount);
        nRet |= 0x1;
   }

    if (nSum != nSumCalc)
    {
        printf_s("ERROR: The sum of %d through %d should be %d, "
                "but %d was reported!\n",
                SUM_START, SUM_END, nSumCalc, nSum);
        nRet |= 0x10;
    }

    if (bSucceed != (bRets[0] && bRets[1] &&
                     bRets[2] && bRets[3] && bRets[4]))
    {
        printf_s("ERROR: The sum of %d through %d should be %d, "
                 "but %d was reported!\n",
                 SUM_START, SUM_END, nSumCalc, nSum);
        nRet |= 0x100;
    }
}
The parallel section was executed 4 times in parallel.
The sum of the consecutive integers from 1 to 10, is 55
All of the functions, func1 through func5 succeeded!

スケジュール

for ディレクティブに適用されます。

schedule(type[,size])

パラメーター

タイプ
スケジューリングの種類 (dynamic、guided、runtime、または static)

size
(省略可能) 反復のサイズを指定します。 size は整数である必要があります。 type が runtime の場合は無効です。

解説

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

例

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

#define NUM_THREADS 4
#define STATIC_CHUNK 5
#define DYNAMIC_CHUNK 5
#define NUM_LOOPS 20
#define SLEEP_EVERY_N 3

int main( )
{
    int nStatic1[NUM_LOOPS],
        nStaticN[NUM_LOOPS];
    int nDynamic1[NUM_LOOPS],
        nDynamicN[NUM_LOOPS];
    int nGuided[NUM_LOOPS];

    omp_set_num_threads(NUM_THREADS);

    #pragma omp parallel
    {
        #pragma omp for schedule(static, 1)
        for (int i = 0 ; i < NUM_LOOPS ; ++i)
        {
            if ((i % SLEEP_EVERY_N) == 0)
                Sleep(0);
            nStatic1[i] = omp_get_thread_num( );
        }

        #pragma omp for schedule(static, STATIC_CHUNK)
        for (int i = 0 ; i < NUM_LOOPS ; ++i)
        {
            if ((i % SLEEP_EVERY_N) == 0)
                Sleep(0);
            nStaticN[i] = omp_get_thread_num( );
        }

        #pragma omp for schedule(dynamic, 1)
        for (int i = 0 ; i < NUM_LOOPS ; ++i)
        {
            if ((i % SLEEP_EVERY_N) == 0)
                Sleep(0);
            nDynamic1[i] = omp_get_thread_num( );
        }

        #pragma omp for schedule(dynamic, DYNAMIC_CHUNK)
        for (int i = 0 ; i < NUM_LOOPS ; ++i)
        {
            if ((i % SLEEP_EVERY_N) == 0)
                Sleep(0);
            nDynamicN[i] = omp_get_thread_num( );
        }

        #pragma omp for schedule(guided)
        for (int i = 0 ; i < NUM_LOOPS ; ++i)
        {
            if ((i % SLEEP_EVERY_N) == 0)
                Sleep(0);
            nGuided[i] = omp_get_thread_num( );
        }
    }

    printf_s("------------------------------------------------\n");
    printf_s("| static | static | dynamic | dynamic | guided |\n");
    printf_s("|    1   |    %d   |    1    |    %d    |        |\n",
             STATIC_CHUNK, DYNAMIC_CHUNK);
    printf_s("------------------------------------------------\n");

    for (int i=0; i<NUM_LOOPS; ++i)
    {
        printf_s("|    %d   |    %d   |    %d    |    %d    |"
                 "    %d   |\n",
                 nStatic1[i], nStaticN[i],
                 nDynamic1[i], nDynamicN[i], nGuided[i]);
    }

    printf_s("------------------------------------------------\n");
}
------------------------------------------------
| static | static | dynamic | dynamic | guided |
|    1   |    5   |    1    |    5    |        |
------------------------------------------------
|    0   |    0   |    0    |    2    |    1   |
|    1   |    0   |    3    |    2    |    1   |
|    2   |    0   |    3    |    2    |    1   |
|    3   |    0   |    3    |    2    |    1   |
|    0   |    0   |    2    |    2    |    1   |
|    1   |    1   |    2    |    3    |    3   |
|    2   |    1   |    2    |    3    |    3   |
|    3   |    1   |    0    |    3    |    3   |
|    0   |    1   |    0    |    3    |    3   |
|    1   |    1   |    0    |    3    |    2   |
|    2   |    2   |    1    |    0    |    2   |
|    3   |    2   |    1    |    0    |    2   |
|    0   |    2   |    1    |    0    |    3   |
|    1   |    2   |    2    |    0    |    3   |
|    2   |    2   |    2    |    0    |    0   |
|    3   |    3   |    2    |    1    |    0   |
|    0   |    3   |    3    |    1    |    1   |
|    1   |    3   |    3    |    1    |    1   |
|    2   |    3   |    3    |    1    |    1   |
|    3   |    3   |    0    |    1    |    3   |
------------------------------------------------

共有済み

1 つ以上の変数をすべてのスレッド間で共有することを指定します。

shared(var)

パラメーター

var
共有する 1 つ以上の変数。 複数の変数を指定する場合は、変数名をコンマで区切ります。

解説

スレッド間で変数を共有するもう 1 つの方法は、copyprivate 句を使用することです。

shared は次のディレクティブに適用されます。

詳細については、「2.7.2.4 shared」を参照してください。

例

private の使用例については、shared を参照してください。