Parallel processing 如何在OpenMP中使用锁定

Parallel processing 如何在OpenMP中使用锁定,parallel-processing,locking,fortran,openmp,fortran90,Parallel Processing,Locking,Fortran,Openmp,Fortran90,我是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(:,:),allo

我是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
免责声明:我没有使用锁机制的经验,并查看了标准以了解这将如何工作。我可能错了

首先,您的代码有一些问题:这段代码不能用最新版本的gfortran编译。您必须将函数walltime移动到程序的contains部分,并且应该使用omp_lib定义所有必需的函数,并删除产生的重复定义。此外,您必须以标准方式定义锁:

integer(kind=OMP_LOCK_KIND), dimension(n) :: lck
现在回答您的问题:调用OMP_INIT_LOCK会将lck数组初始化为解锁状态。所有线程都将获得此变量的副本。然后开始平行段

在第一个循环中,数组初始化为类似于希尔伯特矩阵的东西,并设置每个锁。 第二个块仅由第一个线程执行,第一个锁被释放。还是没什么有趣的。以下循环由所有线程进入,所有线程都在等待第k个锁,因为omp_set_lock等待,直到获得锁为止。以下omp_unset_lock允许所有其他线程跟随。由于已经释放了第一个锁,所有线程将立即进入内部循环,最后一个线程将释放下一个锁。当此线程释放此锁时,其他线程可能已经在等待此锁


原则上,该算法提供某种形式的同步,以确保在输入数据时已计算出k+1循环所需的数据。

对于错误,我深表歉意。我自己对Fortran一无所知。walltime函数应该放在一个单独的文件中,并与主文件一起编译。我天真地把它放在主文件的开头,就像我们通常用c/c++做的那样。我道歉!非常感谢你的回答。你的解释很清楚。这对我帮助很大。