前田です。

今JavaでMutexとConditionVariableを作っているのですが、Rubyでも
使えると便利かなと思って作ってみました。

class ConditionVariable
  def initialize
    @waiters = []
    @waiters_mutex = Mutex.new
  end
  
  def wait(mutex)
    mutex.unlock
    @waiters_mutex.synchronize {
      @waiters.push(Thread.current)
    }
    Thread.stop
    mutex.lock
  end
  
  def signal
    @waiters_mutex.synchronize {
      t = @waiters.shift
      t.run if t
    }
  end
    
  def broadcast
    @waiters_mutex.synchronize {
      for t in @waiters
	t.run
      end
      @waiters.clear
    }
  end
end

試しにthread.rbのQueueをこれで書いてみました。

class Queue2
  def initialize
    @que = []
    @que_mutex = Mutex.new
    @que_cond = ConditionVariable.new
  end

  def push(obj)
    @que_mutex.synchronize {
      @que.push(obj)
    }
    @que_cond.signal
  end

  def pop(noblock = false)
    result = nil
    @que_mutex.synchronize {
      if @que.length == 0 and noblock
	raise ThreadError, "queue empty"
      end
      while @que.length == 0
	@que_cond.wait(@que_mutex)
      end
      result = @que.shift
    }
    return result
  end

  def empty?
    @que.length == 0
  end

  def length
    @que.length
  end
  alias size length
end

以下のスクリプトで動作を確認しました。

queue = Queue2.new

Thread.start {
  while s = queue.pop
    print s
  end
}
while line = gets
  queue.push(line)
end

で、ここから質問なのですが(^^;、

  def pop(noblock = false)
    result = nil
    @que_mutex.synchronize {
      if @que.length == 0 and noblock
	raise ThreadError, "queue empty"
      end
      while @que.length == 0
	@que_cond.wait(@que_mutex)
      end
      result = @que.shift
    }
    return result
  end

の部分を

  def pop(noblock = false)
    @que_mutex.synchronize {
      if @que.length == 0 and noblock
	raise ThreadError, "queue empty"
      end
      while @que.length == 0
	@que_cond.wait(@que_mutex)
      end
      return @que.shift
    }
  end

とするとreturnのところでブロックするようなのですが、これは
どうしてでしょうか。
# waitからは帰ってきているようです。

-- 
前田 修吾