在Ruby中实现同步障碍

我试图在Ruby中“复制”CUDA的__synchtreads()函数的行为。 具体来说,我有一组需要执行某些代码的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 } 

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

编辑: 50次观看,无人接听! 看起来像赏金的候选人……

让我们实现同步障碍。 它必须预先知道它将处理的线程数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 

整个sync是一个关键部分,即它不能同时由两个线程执行。 因此,对Mutex#synchronize的调用是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? 

事实上,有一个名为barrier的gem完全符合我的描述。

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

可能有让线程彼此等待的优点。 但我认为让线程实际上在“中点”完成更为清晰,因为你的问题显然是线程需要彼此在“中点”的结果。 清洁设计解决方案是让他们完成,交付他们的工作成果,并基于这些开始一个全新的线程集。