2010-06-30 6 views
10

utilizo BrB compartir un origen de datos para diversos procesos de trabajo en Ruby 1.9 que el tenedor con el proceso # tenedor como la siguiente:Traza un estancamiento en Ruby

Thread.abort_on_exception = true 

fork do 
    puts "Initializing data source process... (PID: #{Process.pid})" 
    data = DataSource.new(files) 

    BrB::Service.start_service(:object => data, :verbose => false, :host => host, :port => port) 
    EM.reactor_thread.join 
end

Los trabajadores son bifurcadas de la siguiente manera:

8.times do |t| 
    fork do 
    data = BrB::Tunnel.create(nil, "brb://#{host}:#{port}", :verbose => false) 

    puts "Launching #{threads_num} worker threads... (PID: #{Process.pid})"  

    threads = [] 
    threads_num.times { |i| 
     threads << Thread.new { 
     while true 
      begin 
      worker = Worker.new(data, config) 

      rescue OutOfTargetsError 
      break 

      rescue Exception => e 
      puts "An unexpected exception was caught: #{e.class} => #{e}" 
      sleep 5 

      end 
     end 
     } 
    } 
    threads.each { |t| t.join } 

    data.stop_service 
    EM.stop 
    end 
end

Esto funciona casi a la perfección, pero después de unos 10 minutos de carrera me sale el siguiente error:

bootstrap.rb:47:in `join': deadlock detected (fatal) 
     from bootstrap.rb:47:in `block in ' 
     from bootstrap.rb:39:in `fork' 
     from bootstrap.rb:39:in `'

Ahora bien, este error no me dice mucho sobre dónde está realmente pasando el punto muerto, solo me señala la unión en el subproceso EventMachine.

¿Cómo puedo rastrear en qué punto se bloquea el programa?

+0

Ha intentado poner 'Thread.exit' antes del final de la manzana? – glebm

Respuesta

5

Se está bloqueando la unión en el hilo principal, esa información es precisa. Para rastrear dónde se está bloqueando en la cadena secundaria, intente envolver el trabajo del subproceso en timeout block. Tendrá que eliminar temporalmente el rescate catch-all para la excepción timeout para subir.

Actualmente, el subproceso principal intenta unir todos los subprocesos en orden, bloqueando hasta que finalice. Sin embargo, cada hilo solo se unirá en un OutOfTargetsError. El punto muerto se puede evitar mediante el uso de subprocesos de corta duración y moviendo el ciclo while al padre. Sin garantías, pero tal vez algo como esto?

8.times do |t| 
    fork do 
    running = true 
    Signal.trap("INT") do 
     puts "Interrupt signal received, waiting for threads to finish..." 
     running = false 
    end 

    data = BrB::Tunnel.create(nil, "brb://#{host}:#{port}", :verbose => false) 

    puts "Launching max #{threads_num} worker threads... (PID: #{Process.pid})"  

    threads = [] 
    while running 
     # Start new threads until we have threads_num running 
     until threads.length >= threads_num do 
     threads << Thread.new { 
      begin 
      worker = Worker.new(data, config) 
      rescue OutOfTargetsError 
      rescue Exception => e 
      puts "An unexpected exception was caught: #{e.class} => #{e}" 
      sleep 5 
      end 
     } 
     end 

     # Make sure the parent process doesn't spin too much 
     sleep 1 

     # Join finished threads 
     finished_threads = threads.reject &:status 
     threads -= finished_threads 
     finished_threads.each &:join 
    end 

    data.stop_service 
    EM.stop 
    end 
end 
+0

Hola amigo, ¿hay algo de suerte con este enfoque? – captainpete

2

Tuve el mismo problema y lo utilicé con este fragmento de código.

# Wait for all threads (other than the current thread and 
# main thread) to stop running. 
# Assumes that no new threads are started while waiting 
def join_all 
    main  = Thread.main  # The main thread 
    current = Thread.current # The current thread 
    all  = Thread.list  # All threads still running 
    # Now call join on each thread 
    all.each{|t| t.join unless t == current or t == main } 
end 

Fuente: The Ruby Programming Language, O'Reilly (2008)

Cuestiones relacionadas