OpenMP 句
OpenMP API 内で使用される句へのリンクを提供します。
Visual C++ では、次の OpenMP 句がサポートされています。
一般的な属性:
句 | 説明 |
---|---|
if | ループを並列実行するか順次実行するかを指定します。 |
num_threads | スレッド チーム内のスレッド数を設定します。 |
ordered | ordered ディレクティブをループで使用する場合は、parallel for ステートメントで必須です。 |
schedule | for ディレクティブに適用されます。 |
nowait | ディレクティブの暗黙のバリアをオーバーライドします。 |
データ共有属性:
句 | 説明 |
---|---|
プライベート | 各スレッドに変数の独自のインスタンスが必要であることを指定します。 |
firstprivate | 各スレッドに変数の独自のインスタンスが必要であり、各インスタンスをその変数の値で初期化する (変数が parallel コンストラクトの前に存在するため) ことを指定します。 |
lastprivate | 最後の反復 (for ループ コンストラクト) または最後のセクション (#pragma sections) を実行するスレッドのプライベート バージョンと同じになるように、囲んでいるコンテキストの変数のバージョンを設定することを指定します。 |
shared | 1 つ以上の変数をすべてのスレッド間で共有することを指定します。 |
default | 並列領域内のスコープを持たない変数の動作を指定します。 |
reduction | 各スレッドに対してプライベートである 1 つ以上の変数が、並列領域の最後にあるリダクション演算の対象であることを指定します。 |
copyin | threadprivate 変数に対して、スレッドがメイン スレッドの値にアクセスできるようにします。 |
copyprivate | 1 つ以上の変数をすべてのスレッド間で共有することを指定します。 |
copyin
threadprivate 変数に対して、スレッドがメイン スレッドの値にアクセスできるようにします。
copyin(var)
パラメーター
var
並列コンストラクトの前に存在するので、メイン スレッド内の変数の値で初期化される threadprivate
変数。
解説
copyin
は次のディレクティブに適用されます。
詳細については、「2.7.2.7 copyin」を参照してください。
例
copyin
の使用例については、「threadprivate」を参照してください。
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
並列領域内のスコープを持たない変数の動作を指定します。
default(shared | none)
解説
default
句が指定されていない場合に有効な shared
は、並列領域内の変数を、shared 句で指定されている場合と同様に扱うことを意味します。 none
は、並列領域内で使用される変数が、private、shared、reduction、firstprivate、または lastprivate 句でスコープ設定されていない場合に、コンパイラ エラーが発生することを意味します。
default
は次のディレクティブに適用されます。
詳細については、「2.7.2.5 default」を参照してください。
例
default
の使用例については、「private」を参照してください。
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 parallel コンストラクトを参照してください。
例
// 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
句の使用例については、「schedule」を参照してください。
nowait
ディレクティブの暗黙のバリアをオーバーライドします。
nowait
解説
nowait
は次のディレクティブに適用されます。
詳細については、「2.4.1 for コンストラクト」、「2.4.2 sections コンストラクト」、「2.4.3 single コンストラクト」を参照してください。
例
// 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_threads(num)
パラメーター
num
スレッド数
解説
num_threads
句には、omp_set_num_threads 関数と同じ機能があります。
num_threads
は次のディレクティブに適用されます。
詳細は、2.3 parallel コンストラクトを参照してください。
例
num_threads
句の使用例については、「parallel」を参照してください。
ordered
ordered ディレクティブをループで使用する場合は、parallel for ステートメントで必須です。
ordered
解説
ordered
は for ディレクティブに適用されます。
詳細については、「2.4.1 for コンストラクト」を参照してください。
例
ordered
句の使用例については、「ordered」を参照してください。
private
各スレッドに変数の独自のインスタンスが必要であることを指定します。
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)
reduction
各スレッドに対してプライベートである 1 つ以上の変数が、並列領域の最後にあるリダクション演算の対象であることを指定します。
reduction(operation:var)
パラメーター
operation
並列領域の最後にある変数 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!
schedule
for ディレクティブに適用されます。
schedule(type[,size])
パラメーター
type
スケジューリングの種類 (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」を参照してください。
例
shared
の使用例については、「private」を参照してください。