[lnkForumImage]
TotalShareware - Download Free Software

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


 

Forums >

comp.lang.ruby

Thread#raise, Thread#kill, and timeout.rb are unsafe

Charles Oliver Nutter

2/25/2008 7:18:00 AM

I wrote up an article on Thread#raise, Thread#kill, and timeout.rb that
I hope can start making the rounds. Long story short, neither
Thread#raise nor Thread#kill is safe to use, and as a result all
libraries that call them are also unsafe (including timeout.rb, net/*,
and many other libraries in the wider world).

Have a look, add comments, discuss. Hopefully we can find a way to fix
this, because it's going to hold Ruby back until we do.

http://headius.blogspot.com/2008/02/rubys-threadraise-threadkill-time...

- Charlie

4 Answers

Robert Klemme

3/13/2008 4:54:00 PM

0

2008/2/25, Charles Oliver Nutter <charles.nutter@sun.com>:
> I wrote up an article on Thread#raise, Thread#kill, and timeout.rb that
> I hope can start making the rounds. Long story short, neither
> Thread#raise nor Thread#kill is safe to use, and as a result all
> libraries that call them are also unsafe (including timeout.rb, net/*,
> and many other libraries in the wider world).
>
> Have a look, add comments, discuss. Hopefully we can find a way to fix
> this, because it's going to hold Ruby back until we do.
>
> http://headius.blogspot.com/2008/02/rubys-threadraise-threadkill-time...

There is a typo: your second example misses the "main." before the raise. :-)

I have to think a bit more about this, but one remark: IMHO the
locking should be outside the begin end block. Reason is, that if
locking fails for a reason you would not want / need to unlock.

At the moment I'm pondering implications of these options:

main = Thread.current
timer = Thread.new { sleep 5; main.raise }
lock(some_resource)
begin
do_some_work
ensure
unlock_some_resource
timer.kill # moved downwards
end


main = Thread.current
timer = Thread.new { sleep 5; main.raise }
begin
lock(some_resource)
begin
do_some_work
ensure
unlock_some_resource
end
ensure
timer.kill # separate ensure
end

The last one has the added benefit that you can implement it in a
method with a block because timer code is not interleaved with work
code.

But both have the disadvantage that you risk getting a timeout
exception during unlock - which would be unfortunate. OTOH, killing
the timer before the lock release can violate the timing constraint if
the unlocking takes longer - not very likely.

Nasty issues; we had some similar issues with changed timeout handling
of a TX manager in JBoss. Basically the old TX manager was able to
bust an otherwise perfect transaction by timing out in the 2PC
process. :-))

Kind regards

robert

--
use.inject do |as, often| as.you_can - without end

Roger Pack

3/14/2008 4:01:00 PM

0

Charles Oliver Nutter wrote:
> I wrote up an article on Thread#raise, Thread#kill, and timeout.rb that
> I hope can start making the rounds. Long story short, neither
> Thread#raise nor Thread#kill is safe to use, and as a result all
> libraries that call them are also unsafe (including timeout.rb, net/*,
> and many other libraries in the wider world).
>
> Have a look, add comments, discuss. Hopefully we can find a way to fix
> this, because it's going to hold Ruby back until we do.
>
> http://headius.blogspot.com/2008/02/rubys-threadraise-threadkill-time...
>
> - Charlie

It was the problems with timeout that make me wish we had an
EnsureCritical (an Ensure that gets Thread.critical=true set to it
before entering it), so that timeouts can end properly.
Just my $.02
--
Posted via http://www.ruby-....

MenTaLguY

3/14/2008 6:45:00 PM

0

On Sat, 15 Mar 2008 01:00:49 +0900, Roger Pack <rogerpack2005@gmail.com> wrote:
> It was the problems with timeout that make me wish we had an
> EnsureCritical (an Ensure that gets Thread.critical=true set to it
> before entering it), so that timeouts can end properly.

Anything using Thread.critical has its own problems, particularly
when native threads are involved. It can easily result in deadlocks
if the running thread inadvertently tries to use something which another
stopped thread is using (imagine a thread stopped halfway through
releasing a lock that the ensure block needs to acquire, for example
-- something which would have worked fine with normal use of locks, but
becomes a problem once threads can "stop the world").

-mental


Charles Oliver Nutter

3/22/2008 6:06:00 AM

0

MenTaLguY wrote:
> On Sat, 15 Mar 2008 01:00:49 +0900, Roger Pack <rogerpack2005@gmail.com> wrote:
>> It was the problems with timeout that make me wish we had an
>> EnsureCritical (an Ensure that gets Thread.critical=true set to it
>> before entering it), so that timeouts can end properly.
>
> Anything using Thread.critical has its own problems, particularly
> when native threads are involved. It can easily result in deadlocks
> if the running thread inadvertently tries to use something which another
> stopped thread is using (imagine a thread stopped halfway through
> releasing a lock that the ensure block needs to acquire, for example
> -- something which would have worked fine with normal use of locks, but
> becomes a problem once threads can "stop the world").

And to clarify, this problem isn't restricted to native threads...even a
green-threaded model could deadlock if one thread goes critical while
other threads are holding unrelated locks.

- Charlie