I have some serial code:
double* a = malloc((1000000) * sizeof(double));
double* b = malloc((1000000) * sizeof(double));
double totalA = 0;
for (int i = 0; i < 1000000; i++) {
if (i == 0) {
a[i] = sin(i);
}
b[i] = sin(i+1);
if (i < 1000000-1) {
a[i+1] = b[i];
}
totalA += a[i];
}
The output of totalA
after this serial loop is 0.232883978073
.
I then have an OpenMP version of this (note: all variables are re-initialised):
double* a = malloc((1000000) * sizeof(double));
double* b = malloc((1000000) * sizeof(double));
double totalA = 0;
#pragma omp parallel for reduction(+:totalA)
for (int i = 0; i < 1000000; i++) {
if (i == 0) {
a[i] = sin(i);
}
b[i] = sin(i+1);
if (i < 1000000-1) {
a[i+1] = b[i];
}
totalA += a[i];
}
However, the output of totalA
from this code is -0.733714826779
.
I can't figure out for the life of me why it is different.
Thanks.
UPDATE
After some more playing around it seems that the if
statements within the loop are ignored oddly. The actual statements within the if
blocks are executed on all iterations of the loop (as if the if
clause doesn't exist).
For example, changing the if
block to:
if (i < 555555) {
a[i+1] = b[i];
}
seems to make absolutely no difference.
I am still none the wiser as to what is going on here.
Your code contains a race condition. The conflicting statements are the assignment
a[i+1] = b[i];
that writes to the arraya
and the statementtotalA += a[i];
that reads froma
.In your code there is no guarantee that the iteration that is responsible for writing to a particular location in the array is executed before the iteration that reads from that location.
To further demonstrate the issue, ordering the loop segment that contains the conflicting statements resolves the problem (but is most likely devastating for your performance):
It is probably better to avoid the problem altogether and rewrite your program to get rid of the loop-carried dependency:
Finally, note that, as
sin(0) ≈ 0.0
, the statementscan simply be replaced by