2012-02-29 4 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#join вместо 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 помещает текущий поток в состояние ожидания и планирует другой поток. Теперь первый поток удерживает мьютекс так, чтобы какой-либо другой поток был запланирован в следующем порядке, ожидая, что остановленный поток освободит мьютекс, которого никогда не произойдет. Тупик.

+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

Вы не можете использовать переменную т внутри нити. Попробуйте использовать 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)