如何使用锁定例程和睡眠功能以摆脱显式的同步障碍?

How to use the lock routines and the sleep function in order to get rid of the explicite barriers of synchronization?

我实现了以下测试代码:

program test
  use OMP_LIB
  implicit none
  integer::num_thread,nthreads
  integer::a=1
  integer(kind = OMP_lock_kind) :: lck !< a lock
  call omp_init_lock(lck)
  !$OMP PARALLEL SHARED(a,lck) PRIVATE(num_thread,nthreads)
  num_thread=OMP_GET_THREAD_NUM() !< le rang du thread 
  nthreads=OMP_GET_NUM_THREADS() !< le nombre de threads

  if (num_thread==0) then
     call omp_set_lock(lck)
     a=a+5
     a=a+7
     call omp_unset_lock(lck)
  end if
  
  !$OMP BARRIER 
  
  if (num_thread == 1) then
     a=a+1
  end if

  !$OMP BARRIER 
  if (num_thread == 2) then
     a=a+1
  end if

  !$OMP BARRIER 
  if (num_thread == 3) then
     a=a+1
  end if

  !$OMP END PARALLEL
  call omp_destroy_lock(lck)
  
  print*,'a is equal to: ',a
  
contains
  recursive subroutine system_sleep(wait)
    use,intrinsic :: iso_c_binding, only: c_int
    integer,intent(in) :: wait
    integer(kind=c_int):: waited
    interface
       function c_usleep(msecs) bind (C,name="usleep")
         import
         integer(c_int) :: c_usleep
         integer(c_int),intent(in),VALUE :: msecs
       end function c_usleep
    end interface
    if(wait.gt.0)then
       waited=c_usleep(int(wait,kind=c_int))
    endif
  end subroutine system_sleep

  recursive subroutine wait(full)
    logical,intent(in)::full
    do
       call system_sleep(1)
       if (full .eqv. .true.) EXIT

    end do
  end subroutine wait
end program test

如您所见,线程仅更新整数 a 的值。 我想摆脱第一个同步障碍并用代码块替换它。为此,我考虑使用 sleep 函数和锁定例程以避免并发问题。 通过执行这段代码,我得到: a is equal to: 16.

以下代码是没有第一个同步屏障的实现:

program test
  use OMP_LIB
  implicit none
  integer::num_thread,nthreads
  integer::a=1
  integer(kind = OMP_lock_kind) :: lck !< a lock
  call omp_init_lock(lck)
  !$OMP PARALLEL SHARED(a,lck) PRIVATE(num_thread,nthreads)
  num_thread=OMP_GET_THREAD_NUM() !< le rang du thread 
  nthreads=OMP_GET_NUM_THREADS() !< le nombre de threads

  if (num_thread==0) then
     call omp_set_lock(lck)
     a=a+5
     a=a+7
     call omp_unset_lock(lck)
  end if

  if (num_thread .ne. 0) then  
     do
        call omp_set_lock(lck)
        if (a==13) then
           exit
        else
           call omp_unset_lock(lck)
           call system_sleep(1)
        end if            
     end do 
     call omp_unset_lock(lck)
  end if


  if (num_thread == 1) then
     a=a+1
  end if

  !$OMP BARRIER 
  if (num_thread == 2) then
     a=a+1
  end if

  !$OMP BARRIER 
  if (num_thread == 3) then
     a=a+1
  end if

  !$OMP END PARALLEL
  call omp_destroy_lock(lck)
  
  print*,'a is equal to: ',a
  
contains
  recursive subroutine system_sleep(wait)
    use,intrinsic :: iso_c_binding, only: c_int
    integer,intent(in) :: wait
    integer(kind=c_int):: waited
    interface
       function c_usleep(msecs) bind (C,name="usleep")
         import
         integer(c_int) :: c_usleep
         integer(c_int),intent(in),VALUE :: msecs
       end function c_usleep
    end interface
    if(wait.gt.0)then
       waited=c_usleep(int(wait,kind=c_int))
    endif
  end subroutine system_sleep

  recursive subroutine wait(full)
    logical,intent(in)::full
    do
       call system_sleep(1)
       if (full .eqv. .true.) EXIT

    end do
  end subroutine wait
end program test

当我 运行 此代码时,我得到一个闪烁的光标并且没有显示任何结果。

我不明白线程为什么以及如何处理这段代码。 我想提一下条件 a==13 是由于线程号 0 (master) 会将 12 添加到 a 的初始值,即 1。我们只在 master 时离开循环线程完成计算并将 a 设置为值 13.

我希望你能帮助我使这段代码工作。

问题是代码

if (num_thread == 1) then
  a=a+1
end if

不在任何类型的屏障后面,因此它可能发生在一个线程上,而另一个线程正在循环中休眠。这意味着当循环中的线程被唤醒时,a 大于 13,因此无法跳出循环。这反过来意味着陷入循环的线程将永远不会到达 !$OMP BARRIER,因此程序将永远挂起。

这可以通过在 a=a+1 部分之前放置一个障碍来解决,或者将退出循环的条件 (if (a==13) then) 替换为更宽松的 if (a>=13) then

您可以使用调试器或通过在整个代码中添加 write 语句来识别此类问题,例如作为

if (num_thread==0) then
  call omp_set_lock(lck)
  a=a+5
  a=a+7
  write(*,*) 'a+=12 done'
  call omp_unset_lock(lck)
end if

write(*,*) 'Thread ', num_thread, ' of ', nthreads, ' at barrier 1'
!$OMP BARRIER