2012-02-01 34 views
22

Tôi đang tìm một giải pháp về vấn đề xử lý ngoại lệ cổ điển. Xem xét đoạn mã sau đây:Xử lý các trường hợp ngoại lệ được nêu trong một chủ đề Ruby

def foo(n) 
    puts " for #{n}" 
    sleep n 
    raise "after #{n}" 
end 

begin 
    threads = [] 
    [5, 15, 20, 3].each do |i| 
    threads << Thread.new do 
     foo(i) 
    end 
    end 

    threads.each(&:join)  
rescue Exception => e 
    puts "EXCEPTION: #{e.inspect}" 
    puts "MESSAGE: #{e.message}" 
end 

Mã này bắt ngoại lệ sau 5 giây.

Nhưng nếu tôi thay đổi mảng thành [15, 5, 20, 3], thì mã trên sẽ bắt ngoại lệ sau 15 giây. Trong ngắn hạn, nó luôn luôn bắt ngoại lệ được nêu ra trong thread đầu tiên.

Bất kỳ ý tưởng nào, tại sao vậy. Tại sao nó không bắt ngoại lệ sau 3 giây mỗi lần? Làm thế nào để tôi nắm bắt được ngoại lệ đầu tiên được nâng lên bởi bất kỳ chủ đề nào?

Trả lời

48

Nếu bạn muốn bất kỳ ngoại lệ chưa được giải quyết trong bất kỳ chủ đề nào khiến trình thông dịch thoát ra, bạn cần đặt Thread::abort_on_exception= thành true. Ngoại lệ chưa xử lý khiến luồng dừng chạy. Nếu bạn không đặt biến này thành true, ngoại lệ sẽ chỉ được nâng lên khi bạn gọi Thread#join hoặc Thread#value cho chuỗi. Nếu được đặt thành true, nó sẽ được nâng lên khi nó xảy ra và sẽ lan truyền tới luồng chính.

Thread.abort_on_exception=true # add this 

def foo(n) 
    puts " for #{n}" 
    sleep n 
    raise "after #{n}" 
end 

begin 
    threads = [] 
    [15, 5, 20, 3].each do |i| 
     threads << Thread.new do 
      foo(i) 
     end 
    end 
    threads.each(&:join) 

rescue Exception => e 

    puts "EXCEPTION: #{e.inspect}" 
    puts "MESSAGE: #{e.message}" 
end 

Output:

for 5 
for 20 
for 3 
for 15 
EXCEPTION: #<RuntimeError: after 3> 
MESSAGE: after 3 

Lưu ý: nhưng nếu bạn muốn bất kỳ trường hợp chủ đề cụ thể để nâng cao ngoại lệ theo cách này có tương tự abort_on_exception= Thread instance method:

t = Thread.new { 
    # do something and raise exception 
} 
t.abort_on_exception = true 
+0

nhờ cho câu trả lời của bạn. Tôi biết về cờ abort_on_exception. Nhưng yêu cầu của tôi là để biết đó là chủ đề đầu tiên để tăng ngoại lệ và sau đó thực hiện một số quyết định về nó. –

+0

@AkashAgrawal, tôi không đưa bạn nhận xét cuối cùng. Bạn sẽ bắt được ngoại lệ đầu tiên (từ thread với sleep 3) trong mệnh đề 'rescue' và ở đây bạn có thể đưa ra quyết định của bạn về nó. Tất cả các chủ đề còn lại sẽ tiếp tục chạy nếu chủ đề chính của bạn sẽ không thoát sau khi ngoại lệ đầu tiên. –

+0

Vì vậy, đây là một mã thử nghiệm. Câu hỏi của tôi là làm thế nào tôi sẽ bắt được ngoại lệ đầu tiên ném từ bất kỳ chủ đề. Bất kỳ chủ đề có thể ném ngoại lệ bất cứ lúc nào. –

2
Thread.class_eval do 
    alias_method :initialize_without_exception_bubbling, :initialize 
    def initialize(*args, &block) 
    initialize_without_exception_bubbling(*args) { 
     begin 
     block.call 
     rescue Exception => e 
     Thread.main.raise e 
     end 
    } 
    end 
end 
+7

Đã bỏ phiếu vì đây chỉ là mã không có giải thích. Cần ý kiến, mô tả về những gì nó làm, tại sao, vv –

+1

Cũng đừng ghi đè các lớp lõi ruby. -1'd – Senjai

+0

Tôi không đồng ý với cả hai nhận xét. – Nakilon

Các vấn đề liên quan