A REDUCTION variable is referred to by name in a subroutine invoked from that region.
The REDUCTION clause is used to perform some sort of recurring mathematical calculation in parallel. A private temporary is created for each task. At the end of the region, the values of these temporaries are combined to update the outer variable. For example, you can add all the temporaries to form the final sum of a number of terms. Inside the construct, references to that variable are replaced by references to the temporary. This transformation is intended to create the same semantics in parallel and sequential mode, while eliminating data races that would otherwise occur in parallel mode if the variable were shared.
Unfortunately, this transformation is not 100% effective. That is, there are ways a thread can access the outer variable while executing the construct. This usually results in different execution semantics in parallel and sequential mode, can create data races, and violates the rules of OpenMP. Generally speaking, the compiler only replaces name references to the outer variable within the bounds of the construct, but this is not sufficient to catch every kind of data reference.
In particular, if a subroutine is called from within the construct, and that subroutine refers by name to a variable listed in the REDUCTION clause in the calling region, then the subroutine reference will bind to the outer variable, not the per-thread temporary. This diagnostic reports this incorrect usage pattern.
One way to repair this defect is to replace the outer variable reference with a parameter. The outer variable can then be passed to the subroutine at all the call sites. If the subroutine needs to modify the outer variable, then the parameter must be passed by reference.
Care must also be taken when accessing a REDUCTION variable through a pointer within the dynamic extent of the construct. If that pointer got its value outside the construct, then it is probably referring to the outer (non-REDUCTION) variable, which again creates the same kinds of problems as discussed above.
ID |
Observation |
Description |
---|---|---|
1 |
Bad memory access |
The place the PRIVATE variable was accessed |
#include <stdio.h> #include <omp.h> int a; void bad_subroutine() { a += 2; // BAD: sets the value of the outer variable by name } void good_subroutine(int &t) { t += 2; // GOOD: a is accessed via reference parameter } int main(int argc, char **argv) { int i; #pragma omp parallel for reduction(+:a) for (i = 1; i < 10; i++) { a += 2; // reference to reduction temporary bad_subroutine(); good_subroutine(a); } printf("%d\n", a); return 0; }
Copyright © 2010, Intel Corporation. All rights reserved.