インテル® C++ コンパイラー 14.0 ユーザー・リファレンス・ガイド
#pragma omp atomic [read|write|update|capture][seq_cst] |
expression-stmt
OR
#pragma omp atomic [capture][seq_cst] |
structured-block
read |
expression-stmt は v = x; 形式になります。 |
write |
expression-stmt は x = expr; 形式になります。 |
update (または指定しない場合) |
expression-stmt は、次のいずれかの形式になります。 x++; x--; ++x; --x; x binop = expr; x = x binop expr; x = expr binop x; |
capture |
expression-stmt は、次のいずれかの形式になります。 v = x++; v = x--; v = ++x; v = --x; v = x binop= expr; x = x binop expr; x = expr binop x; または、structured-block を使用する場合は、次のいずれかの形式になります。 {v = x; x binop= expr} {x binop= expr; v = x} {v = x; x = x binop expr;} {v = x; x = exp binop x;} {x = x binop expr; y = x;} {x = expr binop x; y = x;} {v = x; x = expr; } {v = x; x++;} {v = x; ++x;} {++x; y = x;} {x++; y = x;} {v = x; x--;} {y = x; --x;} {--x; y = x;} {x--; y = x;}} |
x と v (該当する場合) はともにスカラー型の l-value 式です。
アトミック領域の実行中、構文上の複数の x は同じメモリー位置を指定していなければなりません。
v または expr (該当する場合) のいずれも x で指定されたメモリー位置にアクセスしない可能性があります。
expr はスカラー型の式です。
binop は次のいずれかです: +、*、-、/、&、^、|、<<、または >>。
binop、binop=、++、および -- は多重定義演算子ではありません。
式 x binop expr は、数学的に x binop (expr) と等しくなければなりません。
式 expr binop x は、数学的に (expr) binop x と等しくなければなりません。
x が複数回発生する形式で、x が評価される回数は不定です。
x と v (該当する場合) はともにスカラー型の l-value 式です。
アトミック領域の実行中、構文上の複数の x は同じメモリー位置を指定していなければなりません。
v または expr (該当する場合) のいずれも x で指定されたメモリー位置にアクセスしない可能性があります。
expr はスカラー型の式です。
binop は次のいずれかです: +、*、-、/、&、^、|、<<、または >>。
binop、binop=、++、および -- は多重定義演算子ではありません。
x と v (該当する場合) はともにスカラー型の l-value 式です。
アトミック領域の実行中、構文上の複数の x は同じメモリー位置を指定していなければなりません。
v または expr (該当する場合) のいずれも x で指定されたメモリー位置にアクセスしない可能性があります。
expr はスカラー型の式です。
binop は次のいずれかです: +、*、-、/、&、^、|、<<、または >>。
binop、binop=、++、および -- は多重定義演算子ではありません。
アトミック領域のバインドスレッドは、すべてのスレッドです。アトミック領域は、プログラム中のすべてのスレッドがその所属チームに関係なく、複数のアトミック領域によってアクセスされる同じメモリー位置 x への排他アクセスを徹底します。
#pragma omp atomic には、「プログラム全体を通して、メモリー位置 x へのすべてのアトミックアクセスは、同じ型と型パラメーターでなければならない」という制限があります。
次の表は、atomic 構造でそれぞれの節を指定した場合の影響を説明したものです。
節 |
結果 |
|---|---|
| read | ネイティブマシンのワードサイズに関係なく、メモリー位置 x へのアトミックな読み取りが行われます。 |
| write | ネイティブマシンのワードサイズに関係なく、メモリー位置 x へのアトミックな書き込みが行われます。 |
| [update] | 指定された演算子または組込み関数を使用して、メモリー位置 x がアトミックに更新されます。 次の規則も適用されます。
|
| capture | 指定された演算子または組込み関数でメモリー位置 x がアトミックに更新されます。また、アトミックな更新時に、メモリー位置 x の元の値または最後の値もキャプチャーされます。 次の規則も適用されます。
メモリー位置 x の読み取りと書き込みの間にタスク・スケジュール・ポイントはありません。 |
2 つ以上の atomic 構造を組み合わせることで、メモリー位置 x への排他アクセスを行うことができます。
同期処理をせずに 2 つのスレッドが同じ共有変数にアクセスし、少なくとも一方のスレッドがその変数を変更する場合、データ競合が発生し、予期しない結果を引き起こすことがあります。 競合を回避するには、メモリー位置 x へ並列にアクセスする可能性がある場合、atomic 構造を使用して該当するすべてのアクセスを保護する必要があります。
アトミック領域は、OpenMP* のロックが実行タスクによって保有されている間、または reduction 節の実行中は、critical 領域あるいは ordered 領域であっても、領域外の同じメモリー位置 x への排他アクセスを保証しません。
ただし、ほかの OpenMP* の同期を使用することで、排他アクセスを指定することができます。 例えば、x への一連のアトミックな更新の後に barrier プラグマを指定することで、それ以降のアクセスがアトミックアクセスと競合しないようにできます。
seq_cst 節を指定すると、アトミックに実行される操作ですべての変数に対して暗黙のフラッシュ操作が強制されます。これは、C++11/C11 の memory_order_seq_cst アトミック操作と同じ効果があります。
seq_cst 節を指定しないアトミック操作は、C++11/C11 の memory_order_relaxed アトミック操作と同じ効果があります。
次の例は、このプラグマの使用方法を示します。
#pragma omp atomic update
k += n*mass; // k はアトミックに更新されます。
#pragma omp atomic read
tmp = c; // c はアトミックに読み取られます。
#pragma omp atomic write
count = n*m; // count はアトミックに書き込まれます。
#pragma omp atomic capture
{ d = v; v += n; } // v はアトミックに更新されますが、v のオリジナルの値は d に格納されます。
#pragma omp atomic capture
{ o = c++; } // c の古い値を格納してから c をインクリメントします。
#pragma omp atomic capture seq_cst {--x; v = x;} // x の最終値を v に格納して、すべての変数をフラッシュします。