I have the following C code, which I compile with OpenMP:
( int a[100]
is a global array )
int update (int * x, const int c)
{
int v;
#pragma omp atomic capture
{
v = a[*x];
a[*x] = c;
}
return v;
}
Neither of GCC and Clang gives a compiler error. But I doubt that all the operations within the section can really fit in one atomic operation. Is my code equivalent to the following one?
int update (int * x, const int c)
{
int v;
int X = *x;
#pragma omp atomic capture
{
v = a[X];
a[X] = c;
}
return v;
}
I'm answering with the spec in mind, not a specific architecture or compiler.
Your code is not safe if the value of *x
may change during the execution of update
.
The OpenMP standard describes the atomic
construct. The specific structured block for your atomic capture
is
{ v = x; x = expr; }
x
andv
(as applicable) are both l-value expressions with scalar type.- During the execution of an atomic region, multiple syntactic occurrences of x must designate the same storage location.
The last point is violated if *x
is modified.
I would say, that the code for update
itself is valid under the assumption, so the compiler can't complain. But that assumption is up to you to enforce.
Note that your second version is not safe as per the standard. You can however, protect reading the pointer value with another atomic read
:
int update(int * x, const int c)
{
int v;
int X;
#pragma omp atomic read
X = *x;
#pragma omp atomic capture
{
v = a[X];
a[X] = c;
}
return v;
}
This also requires you to protect all writes to *x
's memory. On x86-64
both clang and GCC generate the same code regardless of the atomic read
, but it ensures that your code is safe on all architectures.