On Thu, 21 Feb 2008 03:33:23 +0900, MenTaLguY <mental / rydia.net> wrote:
> The correct approach is to use a synchronization primitive which queues
> notifications, for example a semaphore or a queue, rather than a condition
> variable.  A queued notification can't get "missed" like this.

Specifically, if "Foo::Semaphore" were a counted semaphore class:

 ping = Foo::Semaphore.new(0)
 pong = Foo::Semaphore.new(0)

 def event(wait, notify, message)
   wait.down
   puts message
   notify.up
 end

 threads = (1..10).map {
   [ Thread.new { event(pong, ping, "Ping...") },
     Thread.new { event(ping, pong, "Pong...") } ]
 }.flatten

 pong.up

 threads.each { |t| t.join }

Unfortunately there aren't any good 1.9/JRuby-friendly semaphore
implementations yet.  Here is a very simple portable one (public domain):

 require 'thread'

 class PortableSemaphore
   def initialize(count=0)
     @lock = Mutex.new
     @nonzero = ConditionVariable.new
     @count = count
   end

   def down
     @lock.synchronize do
       @nonzero.wait @lock until @count.nonzero?
       @count -= 1
     end
     self
   end

   def up
     @lock.synchronize do
       @count += 1
       @nonzero.signal
     end
     self
   end
 end

Note that this is how condition variables are intended to be used --
not directly, but as building blocks for more useful primitives.

-mental