以下是我正在为我的项目工作的略有改动的代码片段,我在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以上时,我会在每个列中更改奇怪的数字,导致输出不正确,我在哪里错了,我该怎么办才能修复它?
答案 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
。