2010-10-29 3 views
0

Je programme une application dans Ruby qui crée un nouveau thread pour chaque nouveau travail. Donc, c'est comme un gestionnaire de files d'attente, où je vérifie combien de threads peuvent être démarrés à partir d'une base de données. Maintenant, quand un thread se termine, je veux appeler la méthode pour commencer un nouveau travail (c'est-à-dire un nouveau thread). Je ne veux pas créer de threads imbriqués, donc y a-t-il un moyen de rejoindre/terminer/quitter le thread appelant et de passer le contrôle au thread principal? Juste pour rendre la situation claire, il peut y avoir d'autres threads en cours d'exécution en ce moment.Contrôle de passage de thread Ruby à main

J'ai essayé simplement de rejoindre le thread appelant, si ce n'est pas le thread principal et j'obtiens l'erreur suivante;

"thread 0x7f8cf8dcf438 tried to join itself" 

Toutes les suggestions seront très appréciées.

Merci d'avance.

+0

Est-ce que cela réinvente la roue? Pouvez-vous utiliser l'une des nombreuses files d'attente de messages existantes? –

Répondre

0

Je propose deux solutions:

le premier est effectivement à se joindre à un fil, mais rejoindre doit être appelé depuis le thread principal (en supposant que vous commenciez à tous de la principale vos threads de travail):

def thread_proc(s) 
    sleep rand(5) 
    puts "#{Thread.current.inspect}: #{s}" 
end 

strings = ["word", "test", "again", "value", "fox", "car"] 

threads = [] 
2.times { 
    threads << Thread.new(strings.shift) { |s| thread_proc(s) } 
} 

while !threads.empty? 
    threads.each { |t| 
    t.join 
    threads << Thread.new(strings.shift) { |s| thread_proc(s) } unless strings.empty? 
    threads.delete(t) 
    } 
end 

mais ce procédé est une sorte de inefficace, car la création de threads encore et provoque à nouveau la mémoire et la CPU de tête.

Vous devriez mieux synchroniser une enveloppe fixe de fils en utilisant une réutilisés file d'attente:

require 'thread' 

strings = ["word", "test", "again", "value", "fox", "car"] 

q = Queue.new 
strings.each { |s| q << s } 

threads = [] 
2.times { threads << Thread.new { 
    while !q.empty? 
    s = q.pop 
    sleep(rand(5)) 
    puts "#{Thread.current.inspect}: #{s}" 
    end 
}} 

threads.each { |t| t.join } 
0
t1 = Thread.new { Thread.current[:status] = "1"; sleep 10; Thread.pass; sleep 100 } 
t2 = Thread.new { Thread.current[:status] = "2"; sleep 1000 } 
t3 = Thread.new { Thread.current[:status] = "3"; sleep 1000 } 

puts Thread.list.map {|X| x[:status] } 
#=> 1,2,3 

Thread.list.each do |x| 
    if x[:status] == 2 
    x.kill # kill the thread 
    break 
    end 
end 

puts Thread.list.map {|X| x[:status] } 
#=> 1,3 

« Discussion :: pass » passera le contrôle du planificateur qui peut maintenant programmer tout autre fil. Le fil a volontairement cédé le contrôle au planificateur - nous ne pouvons pas indiquer de passer commande sur un thread spécifique

« discussion # kill » va tuer l'exemple le fil

« Discussion :: liste » retourne la liste de threads

Les threads sont gérés par le planificateur, si vous souhaitez un contrôle explicite, puis extrayez les fibres. Mais il a quelques pièges, les fibres ne sont pas supportées dans JRuby.

également vérifier les variables locales de thread, il vous aidera à communiquer l'état ou la valeur de retour du thread, sans se joindre au thread.

http://github.com/defunkt/resque est une bonne option pour une file d'attente, vérifiez-la. Essayez aussi JRuby si vous allez utiliser beaucoup de threads. C'est un avantage, c'est qu'il va envelopper les fils de java en bonté rubis.

+0

Je n'avais pas vu la première réponse (je l'avais tapée et je suis sortie pour prendre un café). Mais après l'avoir vu, le pool de threads est un must pour le code de qualité de production. – deepak

Questions connexes