为什么OpenMP原子和关键不能给出正确的结果?

use*_*964 3 fortran openmp

我编写了以下Fortran代码来测试atomiccritical

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
Run Code Online (Sandbox Code Playgroud)

输出是

在此输入图像描述

这意味着结果atomiccritical错误.这很奇怪,我认为添加它们可以避免比赛条件.但是,没有同步的第一个循环给出正确的答案,这里没有比赛吗?我的代码出了什么问题?

Vla*_*r F 6

代码中的问题是竞争条件

   !$omp parallel

...
    a=atmp
    b=btmp
...
    !$omp end parallel
Run Code Online (Sandbox Code Playgroud)

所有线程都执行该操作并且它们发生冲突.你想要omp single围绕这些线.

你不需要任何atomiccritical

!$omp do
do i=1,10
    B(I) = B(I)+A(I)
end do
!$omp end do
Run Code Online (Sandbox Code Playgroud)

因为每个线程都在不同的数组元素上运行.

在您的OpenMP规范示例中,问题在于

!$OMP   PARALLEL DO SHARED(X, Y, INDEX, N)
DO I=1,N
  !$OMP       ATOMIC UPDATE
  X(INDEX(I)) = X(INDEX(I)) + WORK1(I)
Run Code Online (Sandbox Code Playgroud)

数组或函数INDEX(I)可以为两个不同的线程返回相同的值,I并且必须保护这种潜在的竞争条件.