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
ループで実行された作業をスレッド間で分割します。
#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 つのスレッド (必ずしもメイン スレッドではない) で実行するように指定するには、代わりに single ディレクティブを使用します。
例
// 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
は、for、sections ディレクティブと共に使用することもできます。
詳細は、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
の使用例については、プライベートを参照してください。