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-timeoutrb.html

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