[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

Exceptions occassionally lost by child threads

Sonny Chee

3/30/2007 5:07:00 AM

Hey Guys,

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?

Sonny.

--
Posted via http://www.ruby-....

3 Answers

Sylvain Joyeux

3/30/2007 7:19:00 AM

0

> 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
--
Sylvain Joyeux

Robert Klemme

3/30/2007 7:55:00 AM

0

On 30.03.2007 09:19, Sylvain Joyeux wrote:
>> 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

It seems to be a property of Thread#join and #value that they will
automatically propagate any uncaught exceptions of the the joined thread:

irb(main):003:0> t=Thread.new { sleep 20; raise "Foo" }
=> #<Thread:0x7ef7ef6c sleep>
irb(main):004:0> begin; t.join; rescue Exception => e; p e; end
#<RuntimeError: Foo>
=> nil

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.ht...

Kind regards

robert

Sonny Chee

3/30/2007 4:56:00 PM

0

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

--
Posted via http://www.ruby-....