首页 > 解决方案 > 当另一个线程同时修改队列时,线程应该如何验证队列是否已满?

问题描述

我昨天在网站上问了一个问题,并收到了关于我的错误来源的答案,但我仍然对如何解决问题感到困惑。所以我试图用排名不是 1 的线程调用的函数替换同步屏障。线程号 1 负责填充队列。

我的想法是线程(等级不等于 1)应该检查队列是否已满。如果不是,他们调用已经预定义的睡眠函数。如果它已满,我们可以确定我们可以通过而不必担心比赛条件。

 if (num_thread==1) then
      do i_task=first_task,last_task
         tasklist_GRAD(i_task)%state=STATE_READY
         call queue_enqueue_data(master_queue,tasklist_GRAD(i_task))   !< add the list elements to the queue (full queue)
      end do
   end if

   if (num_thread .ne. 1) then
      call wait_thread(master_queue)
   end if

!!$       !$OMP BARRIER    !!!!!!! retired OMP BARR
   call master_worker_execution(self,var,master_queue,worker_queue,first_task,last_task,nthreads,num_thread,lck)

这是等待函数的定义:

subroutine wait_thread(master_queue)
    type(QUEUE_STRUCT),pointer,asynchronous::master_queue !< the master queue of tasks
    do while (.not. queue_full(master_queue)) 
       call system_sleep(1) 
    end do
  end subroutine wait_thread

问题是 1 号线程显然会修改名为master_queueso write 的队列,同时其他线程将检查队列是否已满,因此也对其进行修改。这可能导致竞争条件。

下面是queue_full 函数的定义:

recursive logical function queue_full( queue )
    type(QUEUE_STRUCT),asynchronous, intent(in)  :: queue
    !$OMP CRITICAL 
    queue_full = (queue%size == queue%capacity)
    !$OMP END CRITICAL 
  end function queue_full

运行时,我没有收到分段错误,但我也没有得到代码的结果OMP_BARRIER

通常我会显示值,但现在我得到一个闪烁的光标。

我的问题是:有没有办法解决这个问题?是不是不能换了OMP_BARRIER

我试图添加属性asynchronous ,master_queue所以声明变成了这样: type(QUEUE_STRUCT),pointer,asynchronous::master_queue !< the master queue of tasks。定义中的critical 指令queue_full 是我也添加的,但徒劳无功。

请问有什么帮助吗?

编辑: 我刚刚尝试过这种方法,但我不知道它是否真的取代了 OMP_BARRIER。这是新模块time(没什么复杂的,system_sleep 功能wait ):

module time
  use QUEUE
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(1000)
       if (full .eqv. .true.) EXIT 
    end do
  end subroutine wait
end module time

这就是我更换的方式OMP_BARRIER

       full = .false. 
       first_task=5
       last_task=6

       if (num_thread==1) then
          do i_task=first_task,last_task
             tasklist_GRAD(i_task)%state=STATE_READY
             call queue_enqueue_data(master_queue,tasklist_GRAD(i_task))   !< add the list elements to the queue (full queue)
          end do
          full=.true. 
       end if

       if (num_thread .ne. 1) then      !!!!!!!!!! how to replace OMP_BARRIER
          call wait(full)    !!! wait until full equal to true 
       end if


       call master_worker_execution(self,var,master_queue,worker_queue,first_task,last_task,nthreads,num_thread,lck)

我还想补充一点,shared变量full 的类型是logical.

这是摆脱显式障碍的有效方法吗?

标签: multithreadingfortranqueuesynchronizationopenmp

解决方案


推荐阅读