2012-02-29 9 views
2

G'day、スレッドデッドロック

私はRuby 1.9.3を使って簡単なマルチスレッド実験をしようとしていました。

コード:

require 'thread' 

ary = *0..10 

res = 0 
mutex = Mutex.new 
#cv = ConditionVariable.new 

ary.each do |x| 
    p "Iteration no. #{x}" 
    t = Thread.new do 
     p "Thread taking care of #{x}" 
     mutex.synchronize do 
      #cv.wait(mutex) 
      res += x 
      t.stop 
     end 
    end 
end 

Thread.list.each do |t| t.join; end 
puts res 

コール

[email protected]:~/coding$ ruby --version 
ruby 1.9.3p0 (2011-10-30 revision 33570) [x86_64-linux] 
[email protected]:~/coding$ ruby mt.rb 
"Iteration no. 0" 
"Iteration no. 1" 
"Iteration no. 2" 
"Iteration no. 3" 
"Iteration no. 4" 
"Thread taking care of 2" 
"Thread taking care of 1" 
"Thread taking care of 0" 
"Thread taking care of 3" 
"Iteration no. 5" 
"Thread taking care of 4" 
"Iteration no. 6" 
"Thread taking care of 5" 
"Iteration no. 7" 
"Thread taking care of 6" 
"Iteration no. 8" 
"Thread taking care of 7" 
"Iteration no. 9" 
"Thread taking care of 8" 
"Iteration no. 10" 
"Thread taking care of 9" 
"Thread taking care of 10" 
mt.rb:21:in `join': deadlock detected (fatal) 
    from mt.rb:21:in `block in <main>' 
    from mt.rb:21:in `each' 
    from mt.rb:21:in `<main>' 

私はここに、間違って何をしているのですか?私は多くのものを試しました。Thread#stopの代わりにを呼び出し、完了したときにはThreadメソッドを呼び出しません。

ありがとうございます!


改訂コードは:それはミューテックスを保持している間

require 'thread' 

ary = *0..10 

res = 0 
mutex = Mutex.new 

ary.each do |x| 
    p "Iteration no. #{x}" 
    t = Thread.new do 
     p "Thread taking care of #{x}" 
     mutex.synchronize do 
      res += x 
     end 
     t.stop 
    end 
end 

Thread.list.each &:join 
puts res 

答えて

2

はないstopスレッドを実行してください。 stopメソッドは、現在のスレッドをスリープ状態にし、他のスレッドをスケジュールします。今度は、最初のスレッドがmutexを保持しているので、次にスケジューリングされる他のスレッドが、終了したスレッドが決して起こらないミューテックスを解放するのを待って終了します。デッドロック。

+0

は、あなたの答えをいただき、ありがとうございます。残念ながら、これは動作しません。私は質問の最後に改訂コードを入れました。もしあなたが一見することができたら、私はそれを愛するでしょう。 –

0

@ FranciscoP.ループ内で定義したものがループのローカルに残っている場合、ループ内でスレッドを呼び出すと、ループ外では使用できなくなります。ループ外の変数を定義してスレッドを渡す必要がありますループが完了すると、そのスレッドが利用可能になります。

例えば:

threads = [] 

threads << Thread.new do 
ary.each do |x| 
    p "Iteration no. #{x}" 
     mutex.synchronize do 
      res += x 
     end 
end 
threads.each { |t| t.join } 
0

あなたがスレッドの内部で変数tを使用することはできません。現在のスレッドを示すThread.stopを試してください。次のように:

require 'thread' 

ary = *0..10 

res = 0 
mutex = Mutex.new 

ary.each do |x| 
    p "Iteration no. #{x}" 
    t = Thread.new do 
     p "Thread taking care of #{x}" 
     mutex.synchronize do 
      res += x 
     end 
     Thread.stop 
    end 
end 

Thread.list.each &:join 
puts res 

また、停止したスレッドに参加できるかどうかわかりません。なぜ、参加前に再アクティブ化しないのですか?

Thread.list.each {|t| t.run; t.join } 
puts res 
0

このリストにはメインスレッドが含まれているため、Thread.list.joinを実行することはできません。

あなたがThread.main.joinを実行すると、あなたが自分自身を待っているのでエラーが発生し、それはナンセンスです。

あなたが行うことができ

Thread.list.delete_if { |t| t == Thread.main }.map(&:join)