2010-06-30 11 views
10

tôi sử dụng BrB để chia sẻ một nguồn dữ liệu cho quá trình lao động khác nhau trong Ruby 1.9 mà tôi ngã ba với Process # ngã ba như sau:Trace một bế tắc trong 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

Các công nhân được chia hai như sau:

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

này hoạt động khá nhiều cách hoàn hảo, nhưng sau khoảng 10 phút chạy tôi nhận được lỗi sau:

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 `'

Bây giờ lỗi này không cho tôi biết nhiều về nơi bế tắc thực sự xảy ra, nó chỉ chỉ cho tôi tham gia vào chuỗi EventMachine.

Làm cách nào để theo dõi lại thời điểm chương trình bị khóa?

+0

Các bạn đã thử đặt 'Thread.exit' trước khi kết thúc của khối? – glebm

Trả lời

5

Nó đang khóa khi tham gia vào chuỗi chính, thông tin đó là chính xác. Để theo dõi vị trí khóa của nó trong chủ đề con, hãy thử gói công việc của luồng vào một số timeout block. Bạn sẽ cần phải tạm thời xóa giải cứu toàn bộ cho ngoại lệ hết thời gian chờ để tăng.

Hiện tại, chuỗi chủ đề cố gắng tham gia tất cả các chuỗi theo thứ tự, chặn cho đến khi mỗi chuỗi cho đến khi hoàn tất. Tuy nhiên, mỗi luồng sẽ chỉ tham gia vào một OutOfTargetsError. Có thể tránh được bế tắc bằng cách sử dụng các chuỗi ngắn ngủi và di chuyển vòng lặp while vào cha mẹ. Không có bảo đảm, nhưng có thể một cái gì đó như thế này?

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

Hey dude, bất kỳ may mắn với cách tiếp cận này? – captainpete

2

Tôi đã gặp vấn đề tương tự khi yêu cầu bằng cách sử dụng đoạn mã này.

# 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 

Nguồn: The Ruby ngôn ngữ lập trình, O'Reilly (2008)