在Fortran中与OMP和后端更新阵列并行重叠?

时间:2017-12-05 21:18:13

标签: parallel-processing fortran openmp

以下是我正在为我的项目工作的略有改动的代码片段,我在test1,2,3例程中遇到一个奇怪的并行问题,其中数字有时是错误的:

  integer, parameter :: N=6
  integer, parameter :: chunk_size=3
  integer, dimension(1:N) :: a,b,c

contains

  subroutine array_setup
    implicit none
    integer :: i

    do i=1,N
       a(i)=2*i
       b(i)=i*i
       c(i)=i*i-i+2
    end do

    return
  end subroutine array_setup

  subroutine test1
    implicit none
    integer :: i

    !$OMP parallel do private(i) shared(a,b,c) schedule(static,chunk_size)
    do i=2,N
       a(i-1)=b(i)
       c(i)=a(i)
    end do
    !$OMP end parallel do

    return
  end subroutine test1

  subroutine test2
    implicit none
    integer :: i

    !$OMP parallel do private(i) shared(a,b,c) schedule(static,chunk_size)
    do i=2,N
       a(i-1)=b(i)
       a(i)=c(i)
    end do
    !$OMP end parallel do

    return
  end subroutine test2

  subroutine test3
    implicit none
    integer :: i

    !$OMP parallel do private(i) shared(a,b,c) schedule(static,chunk_size)
    do i=2,N
       b(i)=a(i-1)
       a(i)=c(i)
    end do
    !$OMP end parallel do

    return
  end subroutine test3

end program vectorize_test

下面是OMP_NUM_THREADS = 1时输出的示例:

 after setup
           1           2           1           2
           2           4           4           4
           3           6           9           8
           4           8          16          14
           5          10          25          22
           6          12          36          32
 after test1
           1           4           1           2
           2           9           4           4
           3          16           9           6
           4          25          16           8
           5          36          25          10
           6          12          36          12
 after test2
           1           4           1           2
           2           9           4           4
           3          16           9           8
           4          25          16          14
           5          36          25          22
           6          32          36          32
 after test3
           1           2           1           2
           2           4           2           4
           3           8           4           8
           4          14           8          14
           5          22          14          22
           6          32          22          32

但是,当我将线程数增加到1以上时,我会在每个列中更改奇怪的数字,导致输出不正确,我在哪里错了,我该怎么办才能修复它?

1 个答案:

答案 0 :(得分:2)

当你这样做时

!$OMP parallel do private(i) shared(a,b,c) schedule(static,chunk_size)
do i=2,N
   a(i-1)=b(i)
   c(i)=a(i)
end do
!$OMP end parallel do

你可以有一个线程读取值a(i)尚未计算,因为它被安排用于其他一些线程。循环迭代取决于前一个迭代。你不能以这种方式并行化它。您还可以让一个线程读取与其他线程正在编写的a(i)位置相同的位置。这也是一个错误(竞争条件)。

循环

!$OMP parallel do private(i) shared(a,b,c) schedule(static,chunk_size)
do i=2,N
   a(i-1)=b(i)
   a(i)=c(i)
end do
!$OMP end parallel do

迭代也不是独立的。请注意,a(i)的大多数位置将在下一次迭代中被覆盖。同样,两个线程可能会按顺序发生冲突,这两个操作应该完成。耀可以安全地将其重写为

a(1) = b(2)
!$OMP parallel do private(i) shared(a,b,c) schedule(static,chunk_size)
do i=2,N
   a(i)=c(i)
end do
!$OMP end parallel do

第三个循环

!$OMP parallel do private(i) shared(a,b,c) schedule(static,chunk_size)
do i=2,N
   b(i)=a(i-1)
   a(i)=c(i)
end do
!$OMP end parallel do

与第一个循环有同样的问题。每次迭代都取决于前一次迭代的值。这不容易并行化。您必须找到一种如何重写算法的方法,以便迭代不会相互依赖。

请注意,每个子例程中return都没有。如果您在父作用域中有它,则在每个子例程中也不需要implicit none