From: Brent Roman Date: 2007-12-31T14:46:51+09:00 Subject: Re: Experimental PATCH to improve thread performance Charlie, If we both agree it's worthwhile, let's keep chipping away at this... Charles Oliver Nutter-2 wrote: > > > So if we have > > begin > .. > ensure > blocking_operation > critical_cleanup > end > > If an exception were raised immediately after the blocking operation > completed, wouldn't it prevent the ensure from running to completion? > > As I mentioned in a previous post, if one must make a blocking_operation uninterruptible, one could code it as follows: begin .. #recall that Thread.interruptible defaults to false ensure # Thread.interruptible always going to be false here Thread.uninterruptible { #Thread.interruptible=:never within this block blocking_operation critical_cleanup } end Note that this whole construct IS ATOMIC because a thread's default interruptible status is false. Synchronous exceptions do not change a thread's interruptible status and asynchronous exceptions (i.e. interrupts, typically raised by other threads) will be deferred until the target thread's interruptible status is set to true, either explicitly or by blocking. Recall that, just before processing any external exception the thread's interrupt status is aways reset to false. This is what keeps the construct safe, even when there is a whole stack full of ensure clauses to unwind. I did not invent this idea. In fact, this is the way that many microprocessors deal with hardware interrupts at the machine code level. I learned it as a teenager when I started programming real-time industrial control systems in Intel 8086 assembly language. (in the late 1970's!) I'm just proposing that Ruby respond to asynchronous exceptions the much same way that microprocessors process hardware interrupts. You are correct in asserting that coding changes will be required for dealing with your "blocking during cleanup" example. However, I would hope that most applications try to avoid blocking during critical sections, because doing so is just asking for trouble. You either are going to cleave atomic operations in two, as you say, or you run the risk of the system becoming unresponsive if the blocking operation does not complete in a timely fashion. In any case, enclosing a few critical blocking cleanups in Thread.uninterruptible{} will not be terribly difficult. Although, finding all of them may be a bit of a challenge. Charles Oliver Nutter-2 wrote: > > > I would disagree that Thread#raise is intended as a way to pass any sort > of information. I think it's a way to kick a thread back to > responsiveness without killing it. But it's still unsafe as it exists > today. > > Exceptions synchronize and carry information between threads. That is the definition of communication. In my Ruby code, I like to create derived Exception classes that include status about specific failures. For example, when a robot motor overloads, I throw a ServoException that includes the position, velocity and force on the joint at exact instant of failure. class ServoException < RuntimeException attr_reader :position, :velocity, :force end I feel this is a very appropriate use of Exceptions. However, using them as a replacement for Queues and the like in normal data transfers between threads is, as you point out, very inefficient and likely to be non-deterministic (i.e. unsafe). Charles Oliver Nutter-2 wrote: > > > It's also provably unsafe to be able to > arbitrarily interrupt a blocking operation. Does it leave a file locked? > a channel open? In Java, interrupting a thread that's blocking on > low-level IO forces the IO channel into a dead state, since it's > impossible to guarantee that it hasn't been irreversibly corrupted. > > The way to solve this--and really the only way to make it safe--is to > use non-blocking operations instead. This is how all major > multi-threaded workhorse applications are designed...they avoid blocking > as much as possible and simulate blocking operations by feeding > operations to a non-blocking worker and waiting for responses. > > This is really worrisome. What you are saying amounts to an admission that there is no way to make native threads work as flexibly as green threads. Recall that green threads must change all the blocking I/O operations into non-blocking ones. Thus, in Ruby 1.8 and 1.6 all I/O is non-blocking at the OS level -- where all that tricky file state ultimately resides. In Ruby 1.9, I/O is blocking at the OS level. So, are you saying that, in 1.9 (and possibly JRuby), applications would be required to avoid blocking I/O to ensure thread safety? I'm no Java expert, but, there appear to be some that disagree with you here. Just after reading this post, I found this talk in a snail mail invitation to attend SD West 2008: Thousands of Threads and Blocking I/O: The Old Way to Write Java Servers Is New Again (and Way Better) Speaker: Paul Tyma (Software Engineer, Google Inc.) https://www.cmpevents.com/SDw8/a.asp?option=G&V=3&id=543518 Is there really no way to create thread safe applications that use blocking I/O? Or, as Paul Tyma suggests, is this view largely a result of old, flawed JVM implementations? In any case, if blocking I/O is such a problem for thread safety, why not just convert all blocking I/O requests in JRuby to non-blocking ones in Java? As you said to me, be patient and explain if I'm not "getting it" yet. - brent -- View this message in context: http://www.nabble.com/Experimental-PATCH-to-improve-thread-performance-tp14409855p14554571.html Sent from the ruby-core mailing list archive at Nabble.com.