我试图“复制” CUDA的行为__synchtreads()
在Ruby中的功能。 具体来说,我有一组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 }
什么工具,我需要用它来做到这一点? 我试图用一个全球性的哈希值,然后睡觉,直到所有的线程都设置一个标志,指示他们与代码的第一部分完成。 我不能让它正常工作; 它导致挂起和死锁。 我想我需要使用的组合Mutex
和ConditionVariable
,但我不能确定,为什么/如何。
编辑: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
。
当降低值@count
为正的线程被冻结。 路过互斥体作为参数调用ConditionVariable#wait
关键是要防止死锁。 它使互斥冻结线程之前解锁。
一个简单的实验开始1K线程并使得它们添加元素添加到数组。 首先,他们加个零,那么它们同步,并添加的。 预期的结果是一个排序后的数组具有2k个元素,其中每千是零和1K的。
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?
作为事实上,有一个名为屏障宝石这不正是上述我。
最后要注意,不要使用睡在这样的情况下等待。 这就是所谓的忙等待和被认为是不好的做法 。
有可能是具有线程等待对方的优点。 但我认为,它是清洁有螺纹实际上是在“中点”完成的,因为你的问题很明显impliest该线程需要彼此的结果的‘中点’。 简洁的设计解决方案是让他们完成,提供他们工作的结果,并开始一组全新的基于这些线程。