I have written the following Fortran code to test atomic and critical
program test
implicit none
integer::i
integer::a(10),b(10),atmp(10),btmp(10)
a=[1,2,3,4,5,6,7,8,9,10]
b=[12,32,54,77,32,19,34,1,75,45]
atmp=a
btmp=b
write(*,'(1X,10I4)') a+b
print*,'------------------'
!$omp parallel
!$omp do
do i=1,10
B(I) = B(I)+A(I)
end do
!$omp end do
!$omp single
write(*,'(1X,10I4)') b
!$omp end single
a=atmp
b=btmp
!$omp do
do i=1,10
!$omp critical
B(I) = B(I)+A(I)
!$omp end critical
end do
!$omp end do
!$omp single
write(*,'(1X,10I4)') b
!$omp end single
a=atmp
b=btmp
!$omp do
do i=1,10
!$omp atomic
B(I) = B(I)+A(I)
!$omp end atomic
end do
!$omp end do
!$omp single
write(*,'(1X,10I4)') b
!$omp end single
!$omp end parallel
end program
The output is

It means that result of atomic and critical is wrong. This is strange, I thought adding them could avoid racing condition. However, the first loop without synchronization gives right answer, is there no racing here? What is wrong with my code?
The problem in your code is the race condition
!$omp parallel
...
a=atmp
b=btmp
...
!$omp end parallel
all threads do that operation and they clash. You want omp single around these lines.
You don't need any atomic or critical in
!$omp do
do i=1,10
B(I) = B(I)+A(I)
end do
!$omp end do
because each thread operates on a different array element.
In your example from the OpenMP specification the issue is that in
!$OMP PARALLEL DO SHARED(X, Y, INDEX, N)
DO I=1,N
!$OMP ATOMIC UPDATE
X(INDEX(I)) = X(INDEX(I)) + WORK1(I)
the array or function INDEX(I) can return the same value for two different threads with a different I and you must protect this potential race condition.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With