ここでは、OpenMP* *atomic 操作の高度な用法について説明します。
これらの高度な atomic 操作では、read、write、update、capture、および seq_cst などの atomic 構造の後で節を使用します。atomic の節の引数を省略した場合、デフォルトでは update 節が適用されます。
これらの節は、OpenMP* 3.1 と 4.0 仕様に含まれるため、これらの高度な atomic 節をサポートしているインテル® Fortran コンパイラー・クラッシックなどが必要です。
次の C/C++ の例は、read と write 節を個別に使用しています。
int atomic_read(const int *x)
{
int value;
/* *x の値全体をアトミックに読み取ります。 *//* 読み取り操作中に *x は変更されません。 */
#pragma omp atomic read
value = *x;
return value;
}
void atomic_write(int *x, int value)
{
/* 値を *x にアトミックに保存します。 */
/* 書き込み操作全体が完了するまで、*x は変更されません。 */
#pragma omp atomic write
*x = value;
}次の Fortran の例では、read と write 節を使用します。
function atomic_read(x)
integer :: atomic_read
integer, intent(in) :: x ! x の値が全体でアトミックに読み取られることを指示します。
! 読み取り操作中に x は変更されません。
!$omp atomic read
atomic_read = x
return
end function atomic_read
subroutine atomic_write(x, value)
integer, intent(out) :: x
integer, intent(in) :: value ! 値はアトミックに x に保存されることを指示します。
! 書き込み操作全体が完了するまで、x は変更されません。
!$omp atomic write
x = value
end subroutine atomic_write次の C/C++ の例では、capture 節を使用しています。
#pragma omp parallel for shared (pos)
for (int i=0; i < size; i++) {
if (isValid(data[i])) {
int tmpPos;
// omp atomic capture プラグマを使用
#pragma omp atomic capture
{
tmpPos = pos;
pos = pos+1;
}
// すべての選択した要素のインデックスを index にパックします
// (インデックス値の順番は重要ではありません)。
index[tmpPos] = i;
}
}
index[tmpPos] = i;
}
}
上記の capture 節の例は、次のコードを使用するように変更できます。
// "atomic スワップ" により、次のように記述できます:
newPos = foo();
.
.
.
#pragma omp atomic capture
{
tmpPos = pos;
pos = newPos;
}