Reductions
Our race condition resulted from the need to sum a variable across subsums computed by multiple threads. A similar problem would have occurred for other operations such as multiplication. This pattern is called a reduction . Reductions are so common that OpenMP provides support for them.
We have seen reductions in MPI as a collective communication across processes; OpenMP reductions are similar in that they coordinate results across threads.
A reduction is specified by adding the reduction clause to the parallel for pragma. It also requires the reduction operation and reduction variable.
OpenMP takes care of storing partial results in private variables and combining partial results back into the shared varaible after the loop.
The reduction clause has this syntax: reduction (<op>:<variable>)
C/C++ Operators
| Operator | Operation |
|---|---|
| + | Sum |
| * | Product |
| & | Bitwise and |
| ^ | Bitwise exclusive or |
| && | Logical and |
| max | maximum value |
| min | minimum value |
OpenMP 3.1 or later is required for support of max and min in C/C++, but all recent compilers should implement at least this version.
Syntax:
double area, pi, x;
int i, n;
...
area = 0.0;
#pragma omp parallel for private(x) reduction(+:area)
for (int i=0; i<n; i++) {
x = (i + 0.5)/n;
area += 4.0/(1.0 + x*x);
}
pi = area / n;
Similarly for Fortran
!$omp parallel for private(x) reduction(+:area)
Fortran Operators
| Operator | Operation |
|---|---|
| + | Sum |
| * | Product |
| .iand. | Bitwise and |
| .ior | Bitwise or |
| .ieor. | Bitwise exclusive or |
| .and. | Logical and |
| .or. | Logical or |
| .eqv. | Logical equivalence |
| .neqv. | Logical nonequivalence |
| max | maximum value |
| min | minimum value |
Exercise
Modify the pi-computing code to use an appropriate reduction.
C++
Contents of omp_reduction_area.c
#include <stdlib.h>
#include <stdio.h>
#include <omp.h>
int main() {
double area, pi, x;
int n;
n=1000;
area=0.0;
#pragma omp parallel for private(x) reduction(+:area)
for (int i=0; i< n; i++) {
x=(i+0.5)/n;
area+=4.0/(1.0+x*x);
}
pi=area/n;
printf("Pi is %f\n",pi);
return(0);
}
Download omp_reduction_area.c file
Fortran
Contents of omp_reduction_area.f90
program pie
use omp_lib
implicit none
double precision :: area, pi, x
integer :: i, n
integer :: nthreads
n=10000
area=0.0
!$omp parallel do private(x) reduction(+:area)
do i=1,n
x=(i+0.5d0)/n
area=area+4.0/(1.0d0+x**2)
enddo
!$omp end parallel do
pi=area/n
write(*,'(a,f9.6)') "Pi is ", pi
end program
Download omp_reduction_area.f90 file
Python
Contents of omp_reduction_area.py
import os
from omp4py import *
@omp
def pie(nthreads):
omp_set_num_threads(nthreads)
n=1000
area=0.0
x=0.0
with omp("parallel for private(x) reduction(+:area)"):
for i in range(n):
x=(i+0.5)/n;
area+=4.0/(1.0+x*x);
pi=area/n;
return pi
nthreads=os.cpu_count()
pi=pie(nthreads)
print(f"Pi is {pi:.6f}")
Download omp_reduction_area.py file