在Ruby中实现同步屏障

10

我想在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 }

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

编辑:50个浏览量,没有答案!看来可以考虑赏金...


@sawa,我已经找到了上面代码中的错误,并使其正常工作,但我也愿意接受更简洁的建议。sleep()被认为是不良实践吗? - user2398029
“sleep” 不是一种好的实践。它不是绝对要避免的东西,但尽量在可能的情况下避免使用。我有一种感觉,你可以通过使用 Thread#join 或者使用 Fiber 来解决这个问题。 - sawa
谢谢,我会将 fiber 添加为一个标签。 - user2398029
2个回答

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
sync的整个主体是一个临界区,即不能同时由两个线程执行。因此调用Mutex#synchronize
@count值减少到正数时,线程会被冻结。将互斥锁作为参数传递给ConditionVariable#wait的调用对防止死锁至关重要。这会导致在冻结线程之前解锁互斥锁。
一个简单的实验启动1k个线程并使它们向数组中添加元素。首先添加零,然后进行同步并添加1。预期结果是具有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”的宝石可以完全做到我上面所描述的。
最后,不要在这种情况下使用sleep进行等待。这被称为busy waiting被认为是一种不好的做法

很好的回答,非常有帮助!有一个问题:在向数组中添加元素时(array << 0),是否需要同步?是否可以通过使用线程安全的数组实现来规避这个问题,该实现使用自己的锁?或者这对于此解决方案的工作是必要的吗? - user2398029
mtx 互斥锁的作用是确保线程在写入数组时不会出现竞态条件。你所描述的线程安全数组也可以正常工作。 - Jan

0

让线程等待彼此可能有其优点。但我认为,在“中点”实际上完成线程更加清晰,因为您的问题显然暗示着线程需要在“中点”互相获取结果。干净的设计解决方案是让它们完成工作,交付其工作结果,并基于这些结果启动全新的线程集。


我完全同意,但由于这是为CUDA模拟器而设计的,这有点违背了初衷 :) 我可以根据静态代码分析来拆分内核,但我宁愿不这样做。 - user2398029
在这种情况下,不要理会我之前说的话 :-) - Boris Stitnicky

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接