Issue #3176 has been updated by caleb clausen.


Let me try again to explain this one, from a different point of view. I'm simplifying some things a little bit below, but all the essential parts remain true.

Every platform which implements threads has to have somewhere inside it a queue on which it stores the threads which are ready to run but not actually running yet. The type of this queue influences the behavior of the threading system... if it's a plain FIFO queue, then the threading system can't have thread priorities. In order for thread priorities to work at all, the ready-to-run queue has to be a priority queue. 

Ok, so what does this mean for MRI? The OS-provided ready-to-run queue is present, but it isn't being used. It's always empty. All ruby threads which are ready to run are actually pending on the GIL. That's a mutex, and mutexes have their own queues internally on which they keep all the threads waiting for that mutex. So, the GIL's internal queue is MRI's actual ready-to-run queue. And (I contend) that queue is a FIFO, not a priority queue. Therefore, since MRI's actual ready-to-run queue is a FIFO, MRI does not respect thread priorities.

I have verified that for linux, the queues living inside mutexes are FIFOs. I'm fairly sure this is also the case on nearly every other OS as well.

From this point of view, the fix is fairly obvious. The GIL should be replaced with a priority queue. That is, convert calls to

     $GIL.unlock
into
     Thread.current=$ready_to_run.dequeue
     Thread.current.wake_up!

and calls to

     $GIL.lock
into
     $ready_to_run.enqueue(thread: this_thread, priority: this_thread.priority)

I'm not quite sure what to do with BLOCKING_REGION; I think it requires some slightly special handling but shouldn't be very hard.
----------------------------------------
http://redmine.ruby-lang.org/issues/show/3176

----------------------------------------
http://redmine.ruby-lang.org