Дедлок в рубиновом коде с использованием SizedQueue - PullRequest
6 голосов
/ 10 марта 2010

Я думаю, что столкнулся с фундаментальным недоразумением с моей стороны о том, как работает многопоточность в ruby, и я надеюсь получить некоторое представление.

Я бы хотел иметь простого производителя и потребителя. Во-первых, поток производителя, который извлекает строки из файла и вставляет их в SizedQueue; когда они закончатся, прикрепите несколько жетонов на конце, чтобы потребитель (и) знал, что все сделано.

require 'thread'
numthreads = 2
filename = 'edition-2009-09-11.txt'

bq = SizedQueue.new(4)
producerthread = Thread.new(bq) do |queue|
  File.open(filename) do |f|
    f.each  do |r|
      queue << r
    end
  end
  numthreads.times do
    queue << :end_of_producer
  end
end

Теперь несколько потребителей. Для простоты давайте сделаем, чтобы они ничего не делали.

consumerthreads = []

numthreads.times do
  consumerthreads << Thread.new(bq) do |queue|
    until (line = queue.pop) === :end_of_producer
       # do stuff in here
    end
  end
end

producerthread.join
consumerthreads.each {|t| t.join}

puts "All done"

Насколько я понимаю, (а) поток-производитель заблокирует, как только SizedQueue заполнится, и в конечном итоге вернется к его заполнению, и (b) потребительские потоки будут извлекать из SizedQueue, блокируя, когда он опустошается, и в конце концов заканчивать .

Но в ruby1.9 (ruby 1.9.1p243 (2009-07-16 ревизия 24175) [i386-darwin9]) я получаю ошибку взаимоблокировки соединений. Что тут происходит? Я просто не вижу, где есть взаимодействие между потоками, кроме как через SizedQueue, который должен быть потокобезопасным.

Любое понимание будет высоко ценится.

1 Ответ

3 голосов
/ 10 марта 2010

Ваше понимание верно, и ваш код работает на моей машине, на немного более новой версии Ruby (оба ruby ​​1.9.2dev (2009-08-30 trunk 24705) [i386-darwin10.0.0] и ruby ​​1.9.2dev ( 2009-08-30 багажник 24705) [i386-darwin10.0.0])

...