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