我是OpenMP的新手,发现它有点难以理解OpenMP中的锁是如何工作的。下面是使用Fortran 90编写的用于执行LU分解的示例代码。任何人都可以解释锁在这段代码中的工作原理
program lu
implicit none
integer, parameter :: DP=kind(0.0D0),n=20
!-- Variables
integer :: i,j,k,nthr,thrid,chunk=1
real(kind=DP), dimension(:,:),allocatable :: A,B,L,U
real(kind=DP) :: timer,error,walltime
integer(kind=8), dimension(n)::lck
integer::omp_get_thread_num,omp_get_max_threads
nthr=omp_get_max_threads()
allocate(A(n,n))
allocate(B(n,n))
allocate(L(n,n))
allocate(U(n,n))
!-- Set up locks for each column
do i=1,n
call omp_init_lock(lck(i))
end do
timer=walltime()
!$OMP PARALLEL PRIVATE(i,j,k,thrid)
thrid=omp_get_thread_num();
!-- Initiate matrix
!$OMP DO SCHEDULE(STATIC,chunk)
do j=1,n
do i=1,n
A(i,j)=1.0/(i+j)
end do
call omp_set_lock(lck(j))
end do
!$OMP END DO
!-- First column of L
if (thrid==0) then
do i=2,n
A(i,1)=A(i,1)/A(1,1)
end do
call omp_unset_lock(lck(1))
end if
!-- LU-factorization
do k=1,n
call omp_set_lock(lck(k))
call omp_unset_lock(lck(k))
!$OMP DO SCHEDULE(STATIC,chunk)
do j=1,n
if (j>k) then
do i=k+1,n
A(i,j)=A(i,j)-A(i,k)*A(k,j)
end do
if (j==k+1) then
do i=k+2,n
A(i,k+1)=A(i,k+1)/A(k+1,k+1)
end do
call omp_unset_lock(lck(k+1))
end if
end if
end do
!$OMP END DO NOWAIT
end do
!$OMP END PARALLEL
timer=walltime()-timer
write(*,*) 'n = ',n,' time = ',timer,' nthr = ',nthr
! CHECK CORRECTNESS
do j=1,n
L(j,j)=1
U(j,j)=A(j,j)
do i=j+1,n
L(i,j)=A(i,j)
U(i,j)=0
end do
do i=1,j-1
U(i,j)=A(i,j)
L(i,j)=0
end do
end do
B=0
do j=1,n
do k=1,n
do i=1,n
B(i,j)=B(i,j)+L(i,k)*U(k,j)
end do
end do
end do
error=0.0
do j=1,n
do i=1,n
error=error+abs(1.0/(i+j)-B(i,j))
end do
end do
write(*,*) 'ERROR: ',error
end program lu
下面列出了另一个包含walltime函数的文件。它应该与主文件一起编译。
function walltime()
integer, parameter:: DP = kind(0.0D0)
real(DP) walltime
integer::count,count_rate,count_max
call system_clock(count,count_rate,count_max)
walltime=real(count,DP)/real(count_rate,DP)
end function walltime
答案 0 :(得分:2)
免责声明:我没有使用锁定机制的经验,并查看了标准,以了解这将如何工作。我可能错了......
首先,您的代码存在一些问题:此代码无法使用最新版本的gfortran
进行编译。您必须将函数walltime
移动到程序的contains
部分,并且应使用USE omp_lib
来定义所有必需的函数(并删除生成的重复定义)。此外,您必须以标准方式定义锁:
integer(kind=OMP_LOCK_KIND), dimension(n) :: lck
现在回答您的问题:对OMP_INIT_LOCK
的调用会将您的lck
数组初始化为解锁状态。所有线程都将获得此变量的副本。然后启动并行部分。
在第一个循环中,数组被初始化为类似于 Hilbert矩阵的东西,并且每个锁被设置。
第二个块仅由第一个线程执行,第一个锁定被释放。仍然没有什么有趣所有线程都输入以下循环,并且所有线程都在等待k
次锁定,因为omp_set_lock
等待,直到获得锁定。以下omp_unset_lock
允许所有其他线程跟随。由于已经释放的第一个锁定,所有线程将立即进入内部循环,最后一个线程将释放下一个锁定。到那时,这个线程释放了这个锁,其他线程可能已经在等待这个锁了。
原则上,此算法提供某种形式的同步,以确保在输入时已计算k+1
- 循环所需的数据。