A variable is being incorrectly privatized in the OpenMP datascoping clauses.
Change the data scope of the variable to lastprivate
.
In some parallel loops, variables need to be private to each thread but the
value computed in the last loop iterations needs to be used afterwards. For such
cases, the OpenMP private
scoping is incorrect and lastprivate
must be used
instead.
In the following example, liveOut
is incorrectly marked as private
. When a
variable is marked as private
, each thread is instructed to make its own copy
and the original variable is not updated during parallel execution. As a
result, once the loop is completed, the original liveOut
won't retain the
value from the last iteration:
double example(int m, double *A, double *B, double *C) {
double liveOut;
// liveOut is private but used after the loop, so it should be lastprivate
#pragma omp parallel for private(liveOut) shared(A, B, C)
for (int i = 0; i < m; i++) {
liveOut = A[i] * B[i];
C[i] = C[i] + liveOut;
}
liveOut += 5;
return liveOut;
}
To achieve this behavior, we can use the lastprivate
clause. This allows
subsequent operations on liveOut
to work correctly:
double example(int m, double *A, double *B, double *C) {
double liveOut;
#pragma omp parallel for lastprivate(liveOut) shared(A, B, C)
for (int i = 0; i < m; i++) {
liveOut = A[i] * B[i];
C[i] = C[i] + liveOut;
}
liveOut += 5;
return liveOut;
}
In the following example, liveOut
is incorrectly marked as private
. When a
variable is marked as private
, each thread is instructed to make its own copy
and the original variable is not updated during parallel execution. As a
result, once the loop is completed, the original liveOut
won't retain the
value from the last iteration:
real function example(A, B, C)
use iso_fortran_env, only: real32
implicit none
real(kind=real32), intent(in) :: A(:), B(:)
real(kind=real32), intent(inout) :: C(:)
real(kind=real32) :: liveOut
integer :: i
!$omp parallel do private(i, liveOut) shared(A, B, C)
do i = 1, size(C, 1)
liveOut = A(i) * B(i)
C(i) = C(i) + liveOut
end do
liveOut = liveOut + 5
example = liveOut
end function example
To achieve this behavior, we can use the lastprivate
clause. This allows
subsequent operations on liveOut
to work correctly:
real function example(A, B, C)
use iso_fortran_env, only: real32
implicit none
real(kind=real32), intent(in) :: A(:), B(:)
real(kind=real32), intent(inout) :: C(:)
real(kind=real32) :: liveOut
integer :: i
!$omp parallel do lastprivate(liveOut) private(i) shared(A, B, C)
do i = 1, size(C, 1)
liveOut = A(i) * B(i)
C(i) = C(i) + liveOut
end do
liveOut = liveOut + 5
example = liveOut
end function example
- Data-Sharing Attribute Clauses - OPENMP API Specification: Version 5.0 November 2018 [last checked August 2021]