Testing an Atomic example code I got a strange result.
program atomic
use omp_lib
implicit none
integer, parameter :: num_threads = 4, m = 1000000
integer :: thread_num
integer :: i, j, sum1 = 0, sum2 = 0, tic,toc, rate
real:: time
integer, external :: increment
thread_num = 0
!$ call omp_set_num_threads(num_threads)
!////////// ATOMIC ////////////////////////////////////////////////////////////
CALL system_clock(count_rate=rate)
call system_clock(tic)
!$omp parallel do private(thread_num, j) &
!$omp shared(sum1, sum2)
do i = 0 , m-1
!$ thread_num = omp_get_thread_num()
!$omp atomic
sum1 = sum1 + i
sum2 = sum2 + increment(thread_num, i)
end do
!$omp end paralleldo
print*, "sum 1 = ", sum1
print*, "sum 2 = ", sum2
call system_clock(toc)
time = real(toc-tic)/real(rate)
print*, "Time atomic: ", time, 's'
!////////// CRITICAL ////////////////////////////////////////////////////////////
sum1=0; sum2=0
CALL system_clock(count_rate=rate)
call system_clock(tic)
!$omp parallel do private(thread_num, j) &
!$omp shared(sum1, sum2)
do i = 0 , m-1
!$ thread_num = omp_get_thread_num()
!$omp critical
sum1 = sum1 + i
sum2 = sum2 + increment(thread_num, i)
!$omp end critical
end do
!$omp end paralleldo
print*, "sum 1 = ", sum1
print*, "sum 2 = ", sum2
call system_clock(toc)
time = real(toc-tic)/real(rate)
print*, "Time critical: ", time, 's'
end program atomic
integer function increment (thread_num, j)
implicit none
integer, intent(in) :: thread_num, j
! print*, "Function increment run by thread number: ", thread_num
increment = j
end function increment
sum 1 = -2014260032
sum 2 = -1146784608
Time atomic: 1.13900006 s
sum 1 = -2014260032
sum 2 = -2014260032
Time critical: 4.09000015 s
sum 1 = 1783293664
sum 2 = 1576859165
Time atomic: 0.123999998 s
sum 1 = 1783293664
sum 2 = 1783293664
Time critical: 0.133000001 s
I have two questions:
Why do I get a negative output in the first case?
Why is not sum1 equal to sum2 in atomic outputs?
It was compiled using:
gfortran -Wall -Wextra -fopenmp -O2 -Wall -o prog.exe prueba.f90
./prog.exe
Why do I get a negative output in the first case?
Because the sum operation overflows. From this source one can read:
In computer programming, an integer overflow occurs when an arithmetic operation attempts to create a numeric value that is outside of the range that can be represented with a given number of digits – either higher than the maximum or lower than the minimum representable value
For a m = 10000000
the result is 49999995000000
, which is a value bigger than the maximum value representable with an Integer (32-bit integer) in Fortran.
The second question
Why is not sum1 equal to sum2 in atomic outputs?
Because the atomic clause is only being applied to the operation:
sum1 = sum1 + i
The first problem you can solve by using a data-type that can represent a wider range of numbers. The second problem you can solve as follows:
!$omp atomic
sum1 = sum1 + i
!$omp atomic
sum2 = sum2 + increment(thread_num, i)