According to the OpenMP Specification (v4.0), the following program contains a possible data race due to unsynchronized read/write of i
:
int i{0}; // std::atomic<int> i{0};
void write() {
// #pragma omp atomic write // seq_cst
i = 1;
}
int read() {
int j;
// #pragma omp atomic read // seq_cst
j = i;
return j;
}
int main() {
#pragma omp parallel
{ /* code that calls both write() and read() */ }
}
Possible solutions that came to my mind are shown in the code as comments:
- to protect write and read of
i
with#pragma omp atomic write/read
, - to protect write and read of
i
with#pragma omp atomic write/read seq_cst
, - to use
std::atomic<int>
instead ofint
as a type ofi
.
Here are the compilers-generated instructions on x86_64 (with -O2
in all cases):
GNU g++ 4.9.2: i = 1; j = i;
original code: MOV MOV
#pragma omp atomic: MOV MOV
// #pragma omp atomic seq_cst: MOV MOV
#pragma omp atomic seq_cst: MOV+MFENCE MOV (see UPDATE)
std::atomic<int>: MOV+MFENCE MOV
clang++ 3.5.0: i = 1; j = i;
original code: MOV MOV
#pragma omp atomic: MOV MOV
#pragma omp atomic seq_cst: MOV MOV
std::atomic<int>: XCHG MOV
Intel icpc 16.0.1: i = 1; j = i;
original code: MOV MOV
#pragma omp atomic: * *
#pragma omp atomic seq_cst: * *
std::atomic<int>: XCHG MOV
* Multiple instructions with calls to __kmpc_atomic_xxx functions.
What I wonder is why the GNU/clang compiler does not generate any special instructions for #pragma omp atomic
writes. I would expect similar instructions as for std::atomic
, i.e, either MOV+MFENCE
or XCHG
. Any explanation?
UPDATE
g++ 5.3.0 produces MFENCE
for #pragma omp atomic write seq_cst
. That is the correct behavior, I believe. Without seq_cst
, it produces plain MOV
, which is sufficient for non-SC atomicity.
There was a bug in my Makefile, g++ 4.9.2 produces MFENCE
for CS atomic write as well. Sorry guys for that.
Clang 3.5.0 does not implement the OpenMP SC atomics, thanks Hristo Iliev for pointing this out.
mfence
immediately aftermovl $1, i(%rip)
for the sequentially consistent atomic write. – Fraydamfence
for OpenMP SC atomic write? That is, withi
being of typeint
? My GCC only forstd::atomic<int>
. – Carabinmfence
for SC OpenMP atomic writes. So, the problem was with (my) g++ 4.9.2. – Carabin