3

条件変数を提供する同期キューがあります。

その条件変数は、データがキューに追加されたときに通知します。

私は5つのスレッドを持っています:

Thread.new do
  loop do
    @queue.synchronize {
      cond.wait_until { @queue.has_data? || @queue.finished? }
    }
    # some processing code that can also call @queue.enqueue
  end
end

それから私は:

@queue.enqueue some_data
@threads.each(&:join)

MyQueue#enqueue次のようになります。

def enqueue(data)
  synchronize do
    @pending << v unless queued?(data) || processed?(data) || processing?(data)
    data_cond.signal
  end
end

def finished?
  @started && @processing.empty? && @pending.empty?
end

def has_data?
  !@pending.empty?
end

そして、私は#joinに乗ります

deadlock detected

これはどのように正確にデッドロックを引き起こし、どのように修正しますか?

4

3 に答える 3

2

これは、すべてのスレッドが同じ条件変数でブロックされており、データをエンキューできるスレッドがなく、他のスレッドを解放するという問題なのだろうか。

このコードのコメントに基づいて:

Thread.new do
  loop do
    @queue.synchronize {
      cond.wait_until { @queue.has_data? || @queue.finished? }
    }
    # some processing code that can also call @queue.enqueue
  end
end

「@queue.enqueueも呼び出すことができる処理コード」について言及しているコメントは、これ@queue.enqueueが呼び出される唯一の場所ですか? その場合、すべてのスレッドが条件変数でブロックされ、エンキューを呼び出すことができるポイントに到達できるスレッドはありません。Rubyは、すべてのスレッドが同じエンティティでロックされており、それを解放できるスレッドがないことを検出できるため、デッドロックになります。

実際にキューに入れるだけの別のスレッドがある場合 (これは典型的なプロデューサー/コンシューマーの状況です)、デッドロックを引き起こす可能性がある条件変数も待機しないようにしてください。

于 2012-06-11T10:01:50.890 に答える
1

コードの断片しか投稿していないので、あなたを助けるのは少し難しいです...

work_queue gemを試すか、少なくともソース コードを確認してください。

于 2012-06-11T13:55:46.437 に答える
0

has_data を待つ必要はありませんか? || 終了した?同期ブロックで。コードは次のようになります。

Thread.new do
  loop do
    cond.wait_until { @queue.has_data? || @queue.finished? }
    enq = nil
    @queue.synchronize {
        enq = @queue.pop
    }
    # some processing code that can also call @queue.enqueue
  end
end

その場合、キューの内容を操作する場合にのみ、他のスレッドをロックします。あなたがする必要があるのは、完了のように、キューの状態の変化を同期することです

より良い解決策は、レールのように、すべてのスレッド クリティカル変数をミューテックスでラップすることです。変数への同時アクセスがなくなるため、コードが少し遅くなります。

于 2012-06-05T11:49:20.180 に答える