インテル® C++ コンパイラー 16.0 ユーザー・リファレンス・ガイド

omp atomic

アトミックに実行する必要がある計算を指定します。

構文

#pragma omp atomic [read|write|update|capture][seq_cst]

expression-stmt

OR

#pragma omp atomic [capture][seq_cst]

structured-block

引数

read

expression-stmtv = x; 形式でなければなりません。

write

expression-stmtx = expr; 形式でなければなりません。

update (または指定しない場合)

expression-stmt は、次のいずれかの形式でなければなりません。

  • x++;

  • x--;

  • ++x;

  • --x;

  • x binop = expr;

  • x = x binop expr;

  • x = expr binop x;

capture

structured-block を使用しない場合、expression-stmt は、次のいずれかの形式でなければなりません。

  • v = x++;

  • v = x--;

  • v = ++x;

  • v = --x;

  • v = x binop= expr;

  • x = x binop expr;

  • x = expr binop x;

structured-block を使用する場合、expression-stmt は、次のいずれかの形式でなければなりません。

  • {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 への排他アクセスを徹底します。

atomic プラグマには、「プログラム全体を通して、メモリー位置 x へのすべてのアトミックアクセスは、同じ型と型パラメーターでなければならない」という制限があります。

次の表は、atomic 構造でそれぞれの節を指定した場合の影響を説明したものです。

結果

read

ネイティブマシンのワードサイズに関係なく、メモリー位置 x へのアトミックな読み取りが行われます。

write

ネイティブマシンのワードサイズに関係なく、メモリー位置 x へのアトミックな書き込みが行われます。

[update]

指定された演算子または組込み関数を使用して、メモリー位置 x がアトミックに更新されます。次の規則も適用されます。

  • メモリー位置 x の読み取りまたは書き込みを行うための expr または expr-list の評価は、アトミックで行う必要はありません。
  • メモリー位置 x の読み取りと書き込みの間にタスク・スケジュール・ポイントはありません。

capture

指定された演算子または組込み関数でメモリー位置 x がアトミックに更新されます。また、アトミックな更新時に、メモリー位置 x の元の値または最後の値もキャプチャーされます。次の規則も適用されます。

  • メモリー位置 x の元の値または最後の値は、通常の言語セマンティクスに従い、atomic 構造、構造化ブロック、または文に基づいてメモリー位置 v に書き込まれます。
  • メモリー位置 x への読み取りと書き込みのみアトミックに行われます。
  • メモリー位置 x の読み取りまたは書き込みを行うための expr または expr-list の評価およびメモリー位置 v への書き込みは、アトミックで行う必要はありません。

メモリー位置 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 に格納して、すべての変数をフラッシュします。