Search code examples
copenmppragma

private variables vs reduction in OMP


I am trying to understand how OMP treats different for loop declarations. I have:

int main()
{
   int i, A[10000]={...};
   double ave = 0.0;
   #pragma omp parallel for reduction(+:ave)
   for(i=0;i<10000;i++){
       ave += A[i];
   }

   ave /= 10000;

   printf("Average value = %0.4f\n",ave);
   return 0;
}

where {...} are the numbers form 1 to 10000. This code prints the correct value. If instead of #pragma omp parallel for reduction(+:ave) I use #pragma omp parallel for private(ave) the result of the printf is 0.0000. I think I understand what reduction(oper:list) does, but was wondering if it can be substituted for private and how.


Solution

  • So yes, you can do reductions without the reduction clause. But that has a few downsides that you have to understand:

    1. You have to do things by hand, which is more error-prone:
      • declare local variables to store local accumulations;
      • initialize them correctly;
      • accumulate into them;
      • do the final reduction in the initial variable using a critical construct.
    2. This is harder to understand and maintain
    3. This is potentially less effective...

    Anyway, here is an example of that using your code:

    int main() {
       int i, A[10000]={...};
       double ave = 0.0;
       double localAve;
    
       #pragma omp parallel private( i, localAve )
       {
           localAve = 0;
           #pragma omp for
           for( i = 0; i < 10000; i++ ) {
               localAve += A[i];
           }
           #pragma omp critical
           ave += localAve;
       }
    
       ave /= 10000;
    
       printf("Average value = %0.4f\n",ave);
       return 0;
    }
    

    This is a classical method for doing reductions by hand, but notice that the variable that would have been declared reduction isn't declared private here. What becomes private is a local substitute of this variable while the global one must remain shared.