Common Mistakes in Using OpenMP 2: Atomic
Monday Feb 20, 2006
The following code finds good members in array member[] and stores the indices of the good members in array good_members[].
#define N 1000
struct data member[N];
int good_members[N];
int pos = 0;
void find_good_members()
{
for (i=0; i < N; i++) {
if (is_good(member[i])) {
good_members[pos] = i;
pos ++;
}
}
}
The following is a navie way of parallelizing the above code,
#define N 1000
struct data member[N];
int good_members[N];
int pos = 0;
void find_good_members()
{
#pragma omp parallel for
for (i=0; i < N; i++) {
if (is_good(member[i])) {
good_members[pos] = i; // line a
#pragma omp atomic
pos ++; // line b
}
}
}
In order to avoid data races between different updates of global variable pos, the code puts the increment (at line b) in a atomic construct. However, the code does not work, because there is a data race between the read of pos at line a and write of pos at line b.
Changing the body of the if statement to the following gives the correct result.
int mypos;
#pragma omp critical
{
mypos = pos;
pos ++;
}
good_members[mypos] = i;
In OpenMP 2.5 (the latest Specification), inside a parallel region, the only place where you can safely get the value of a variable that is updated in an atomic region is another atomic region.










