Q: Racing condition in assignment to variable of unknown scope a parallel procedure computes the scalar product of two vectors in the following way

*

*Compute the contribution of the current MPI process using OpenMP reduction. The result is stored in the SHARED variable s_loc


*OpenMP master calls MPI_Allreduce to compute the sum of s_loc over all MPI processes. The result is stored in the SHARED variable s_glob


*Finally, s_glob is assigned to the procedure output argument:
s = s_glob
Note that the scope of s is unknown, because it is defined outside the procedure. In the PRIVATE case, the assignment is just per thread and all is fine. However, if s is SHARED, a racing condition occurs, since s_glob is SHARED. I wonder if this racing condition may pose any problem and, if so, how it could be avoided.
In the following example the MPI part is removed, because it is important only for the scope of variables, but not for the problem itself.
program Scalar_Product
  implicit none
  integer, parameter :: n = 10000000
  real, save :: a(n), b(n)
  real :: ab

  call random_number(a)
  call random_number(b)

  !$omp parallel private(ab)
  ab = ScalarProduct(a, b)
  !$omp end parallel

contains

  real function ScalarProduct(a, b) result(s)
    real, intent(in) :: a(:) ! left operand
    real, intent(in) :: b(:) ! right operand

    real, save :: s_loc, s_glob
    integer :: i

    !$omp master
    s_loc = 0
    !$omp end master

    !$omp do reduction(+:s_loc) schedule(static)
    do i = 1, size(a)
      s_loc = s_loc + a(i) * b(i)
    end do

    !$omp master       ! in the real application
    s_glob = s_loc     ! s_glob is computed using
    !$omp end master   ! MPI_Allreduce

    ! this is the assignment to which the question refers
    s = s_glob

  end function ScalarProduct

end program Scalar_Product

Thanks for any helpful comments!
Joerg

A: I revised the example and think that answers my question.
program Scalar_Product
  integer, parameter :: n = 10000000
  real :: a(n), b(n), ab

  ! skipping initialization of a and b ...
 
  !$omp parallel shared(a,b) private(ab)
  ab = ScalarProduct(a, b)  ! would give a racing condition, if ab is shared
  !$omp end parallel

contains

  function ScalarProduct(a, b) result(s)
    real, intent(in) :: a(:) ! left operand
    real, intent(in) :: b(:) ! right operand
    real, save       :: s    ! force result to be shared
    integer          :: i

    !$omp master
    s = 0
    !$omp end master

    !$omp do reduction(+:s) schedule(static)
    do i = 1, size(a)
      s = s + a(i) * b(i)
    end do

  end function ScalarProduct

end program Scalar_Product

Observations

*

*By declaring the function result save it becomes shared

*This allows to eliminate the problematic assignment inside the function

*However, as the function is called inside a parallel region, its result must be assigned to a private variable to avoid a racing condition

Cheers, Joerg
