9

__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 }

これを実現するには、どのツールを使用する必要がありますか?グローバルハッシュを使用してみて、すべてのスレッドがコードの最初の部分で完了したことを示すフラグを設定するまでスリープしました。正しく動作させることができませんでした。その結果、ハングとデッドロックが発生しました。との組み合わせを使う必要があると思いますMutexが、ConditionVariableその理由/方法がわかりません。

編集: 50ビューと答えなし!賞金の候補のように見えます...

4

2 に答える 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がクリティカルセクションです。つまり、2つのスレッドで同時に実行することはできません。したがって、への呼び出し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?

実際のところ、私が上で説明したことを正確に実行するバリアという名前の宝石があります。

最後に、このような状況で待機するためにスリープを使用しないでください。これはビジーウェイトと呼ばれ、悪い習慣と見なされます。

于 2012-12-07T18:53:46.533 に答える
0

スレッド同士を待たせるメリットがあるかもしれません。しかし、スレッドが実際に「中間点」で終了する方がクリーンだと思います。あなたの質問は、スレッドが「中間点」で互いの結果を必要としていることを明らかに示唆しているからです。クリーンな設計ソリューションは、それらを終了させ、作業の結果を提供し、これらに基づいてまったく新しいスレッドのセットを開始することです。

于 2012-12-08T04:04:28.857 に答える