As I understand it, the correct way to pass exceptions between threads
is to explicitly raise them in the target thread… so something like
this works:
a = Thread.new(Thread.current) { |parent|
…
parent.raise err
}
What I’m curious about is that the following code also seems to work:
a = Thread.new {
begin
puts ‘blue’
sleep 2;
raise ArgumentError.new(‘green’)
rescue Exception => err
puts “Caught: #{err.message}”
raise err
end
}
begin
while a
sleep 1
a = a.join(1)
end
puts ‘yellow’
rescue Exception => err
puts “Caught it again: #{err.message}”
end
#blue #Caught: green #Caught it again: green
However, if i move the sleep 1 statement to after a = a.join(1), the
exception seems to get lost and the output is:
#blue #Caught: green #yellow
Should exceptions automatically propagate from children up to the
parent? And if so, why should the positioning of something as innocuous
as sleep 1 matter?
Should exceptions automatically propagate from children up to the
parent? And if so, why should the positioning of something as innocuous
as sleep 1 matter?
Because you have a timeout on the join (a.join(1))
In the first case it sleeps one second, and waits for ‘a’ to finish. It
works if ‘a’ raises within two seconds. Note that it could also fail
since ‘sleep’ is not perfect and it is possible for the main thread to
reach the timeout on ‘join’ before ‘a’ raises.
In the second case, the main thread only waits ‘a’ for one second. It is
useless because of the sleep(2) in ‘a’.
It should work as expected if you replace a.join(1) by a.join
Thanks guys. My bad. For some reason I thought join(1) returned nil
when the thread completed. That should learn me to post messages when
I’m half asleep:"P
In the following snippet the parent always catches the exception
regardless of the position of the sleep 1 statment.
a = Thread.new {
begin
puts ‘blue’
sleep 2;
raise ArgumentError.new(‘green’)
rescue Exception => err
puts “Caught: #{err.message}”
raise err
end
}
begin
b = a
while a
sleep 1 # position 1
b = a.join(1)
a = b if !a
sleep 1 # position 2
end
puts ‘yellow’
rescue Exception => err
puts “Caught it again: #{err.message}”
end
I think this behavior is documented, although a bit cryptic IMHO:
“If thr had previously raised an exception and the abort_on_exception
and $DEBUG flags are not set (so the exception has not yet been
processed) it will be processed at this time.” http://www.ruby-doc.org/core/classes/Thread.html#M000474
Kind regards
robert
This forum is not affiliated to the Ruby language, Ruby on Rails framework, nor any Ruby applications discussed here.