@m_seki の

I like ruby tooから引っ越し

さらに5分で改造するつづき

http://d.hatena.ne.jp/ita-wasa/20070717をうけて。

チャネルをパターンで指定できるようにしてみる。最終的にはRindaとほぼ同じ実装になると思うけどエッセンスだけ。
deqのパターンと、enqのチャネルを === で比較します。Stringで示したチャネルをRegexpで示すパターンで指定することができます。id:it-wasaさんの形のチャネルではないけれど、大した違いがないので気にしない。
Queueであるので順序を律儀に守るとすると、チャネルごとに事前に分けておくと都合が悪いのでArrayにすべて格納しています。RDBMSと一緒に使うならこの辺りはもっといろいろできそう。
(Rinda同様に)クライアントの数、キューに残ってしまう要素の数などが性能に響いてくると思います。

require 'monitor'

class MailBag
  def initialize
    @ary = []
  end

  def take(pattern)
    idx = @ary.each_with_index { |x, i| break(i) if pattern === x[0] }
    return nil if idx == @ary # not found
    return @ary.delete_at(idx)
  end

  def write(channel, value)
    @ary.push([channel, value])
  end
end

class MailBox
  include MonitorMixin
  def initialize
    super()
    @waiter = []
    @bag = MailBag.new
  end

  def deq(pattern, timeout=nil)
    synchronize do
      while true
        channel, value = @bag.take(pattern)
        return [channel, value] if channel
        cond = new_cond
        @waiter.push([pattern, cond])
        raise MailBoxTimeout unless cond.wait(timeout)
      end
    end
  end

  def enq(channel, value)
    synchronize do
      @bag.write(channel, value)
      wake = []
      stay = []
      @waiter.each do |w|
        dest = (w[0] === channel) ? wake : stay
        dest.push(w)
      end
      @waiter = stay
      wake.each { |w| w[1].signal }
    end
  end

  class MailBoxTimeout < ThreadError; end
end