2010-03-10 7 views
5

Penso di essere di fronte a un malinteso fondamentale da parte mia sul modo in cui il threading funziona in ruby ​​e spero di ottenere qualche intuizione.Deadlock in ruby ​​code usando SizedQueue

Mi piacerebbe avere un semplice produttore e consumatore. Innanzitutto, un thread del produttore che estrae le righe da un file e le inserisce in un SizedQueue; quando quelli finiscono, attaccare alcuni token alla fine per consentire al consumatore (s) sapere che le cose sono fatte.

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 

Ora alcuni consumatori. Per semplicità, facciamoli fare niente.

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" 

mia comprensione è che (a) il filo produttore bloccherà una volta che la SizedQueue è piena e infine tornare a riempirlo, e (b) i fili di consumo tirerà dalla SizedQueue, bloccando quando si svuota e alla fine finire.

Ma sotto ruby1.9 (ruby 1.9.1p243 (revisione 2009-07-16 24175) [i386-darwin9]) Ottengo un errore deadlock sui join. Cosa sta succedendo qui? Semplicemente non vedo dove ci sia un'interazione tra i thread tranne tramite SizedQueue, che dovrebbe essere thread-safe.

Qualsiasi intuizione sarebbe molto apprezzata.

risposta

3

La tua comprensione è corretta e il tuo codice funziona sulla mia macchina, su una versione leggermente più recente di Ruby (sia ruby ​​1.9.2dev (tronco 2009-08-30 24705) [i386-darwin10.0.0] e ruby ​​1.9.2dev (Tronco 08-08-2005 24705) [i386-darwin10.0.0])

+0

Eccellente. Verificato che funzioni con un recente trunk da 1.9. Grazie! –

+0

Nessun problema. Dovresti quindi "accettare" la risposta cliccando sul segno di spunta. –