From: Joel VanderWerf Date: 2007-05-12T03:46:58+09:00 Subject: Re: basic threading question: can ruby use real threads? Bill Kelly wrote: > From: "Sylvain Joyeux" >> >>> The APIs are the same between MRI and JRuby, though JRuby deliberately >>> hedges on the implementation of certain unsafe features like >>> Thread#kill, Thread#raise, and Thread.critical=. >> Thread#raise, "unsafe" ? It is the most useful thread-related >> functionality I've seen since I'm using threads ! It allows for >> instance to handle failing rendezvous the proper way (by using >> exceptions). >> >> Could you tell us why you think it is "unsafe" ? > > Hi, > > I'm not sure if this is what MenTaLGuY meant, but one way that > Thread#raise is unsafe, is that it can raise an exception in the > specified thread while that thread is executing an 'ensure' block. > > This can cause a failure of critical resources to be cleaned up > correctly, such as locks on mutexes, etc., as some or all of the > code in the ensure block is skipped. > > I first ran into this when I tried to use timeout{} to implement > a ConditionVariable#timed_wait, like: > > require 'thread' > require 'timeout' > class ConditionVariable > def timed_wait(mutex, timeout_secs) > timeout(timeout_secs) { wait(mutex) } # THIS IS UNSAFE > end > end > > Note that 'timeout' functions by creating a temporary new thread > which sleeps for the duration, then raises an exception in the > 'current' thread that invoked timeout. > > If the timeout raises its exception at an unlucky moment, the > various internals of ConditionVariable#wait and Mutex#synchronize > that depend on ensure blocks to restore their class invariants are > skipped, resulting in nasty things like a permanently locked mutex. > > Not fun... :( This is disturbing. Is #timeout inherently unsafe, if it is implemented as a thread, even in MRI ruby's green threads? Ruby gives you a lot of freedom to do anything you want inside of ensure clauses, and I guess this means that ensure clauses can't be given special treatment--the ensure clause itself might be what needs to be interrupted by the timeout. That seems to rule out treating ensure clauses as a critical section, for example. And it seems to rule out a method like Thread#raise_unless_in_ensure or Thread#raise_after_ensure_finishes. What if there were two kind of ensure clauses, one which is uninterruptible (to be used only for cleanup that is deterministic) and one which is interruptible (and not guaranteed to finish)? What's the best practice in current MRI ruby? Use Timeout only in cases where you know it is safe, and otherwise use #select timeouts or whatever else is appropriate? -- vjoel : Joel VanderWerf : path berkeley edu : 510 665 3407