在Ruby中实现同步障碍

use*_*029 8 ruby multithreading fibers thread-synchronization

我试图__synchtreads()在Ruby中"复制"CUDA 函数的行为.具体来说,我有一组N需要执行某些代码的线程,然后所有线程都在执行的中间点等待,然后继续执行其余的业务.例如:

x = 0

a = Thread.new do
  x = 1
  syncthreads()  
end

b = Thread.new do 
  syncthreads()
  # x should have been changed
  raise if x == 0
end

[a,b].each { |t| t.join }
Run Code Online (Sandbox Code Playgroud)

我需要使用哪些工具来完成此任务?我尝试使用全局哈希,然后休眠,直到所有线程都设置了一个标志,表明他们已经完成了代码的第一部分.我无法让它正常工作; 它导致了挂起和死锁.我我需要使用的组合MutexConditionVariable,但我不能确定,为什么/如何.

编辑: 50次观看,没有答案!看起来像赏金的候选人......

Jan*_*Jan 8

让我们实现同步障碍.它必须预先知道它将处理的线程数n.在第一次n-1调用sync屏障期间,将导致调用线程等待.电话号码n将唤醒所有线程.

class Barrier
  def initialize(count)
    @mutex = Mutex.new
    @cond = ConditionVariable.new
    @count = count
  end

  def sync
    @mutex.synchronize do
      @count -= 1
      if @count > 0
        @cond.wait @mutex
      else
        @cond.broadcast
      end
    end
  end
end
Run Code Online (Sandbox Code Playgroud)

整体sync是一个关键部分,即它不能同时由两个线程执行.因此呼吁Mutex#synchronize.

当减小的值为@count正时,线程被冻结.将互斥锁作为参数传递给调用ConditionVariable#wait是至关重要的,以防止死锁.它会导致互斥锁在冻结线程之前解锁.

一个简单的实验启动1k个线程,并使它们向数组添加元素.首先,他们添加零,然后他们同步并添加.预期的结果是一个带有2k个元素的排序数组,其中1k是零,1k是1.

mtx = Mutex.new
arr = []
num = 1000
barrier = Barrier.new num
num.times.map do
  Thread.start do
    mtx.synchronize { arr << 0 }
    barrier.sync
    mtx.synchronize { arr << 1 }
  end
end .map &:join;
# Prints true. See it break by deleting `barrier.sync`.
puts [
  arr.sort == arr,
  arr.count == 2 * num,
  arr.count(&:zero?) == num,
  arr.uniq == [0, 1],
].all?
Run Code Online (Sandbox Code Playgroud)

事实上,有一个名为屏障的宝石完全符合我的描述.

最后要注意的是,在这种情况下不要使用睡眠等待.它被称为繁忙的等待,被认为是一种不好的做法.