@m_seki の

I like ruby tooから引っ越し

Fibered TupleSpace

Rindaをシングルスレッドで書けるかやってみたら書けそうな感じ。使い道ないけど!

まず、includeしたMonitorMixinの抜き方がわからなかったので、どうしようかと思ったけど、super()しなければ良いことに気づいた。
それから、synchronizeはただのyieldにした。

module Rinda
  class TupleSpace
    def initialize(period=5)
      @bag = TupleBag.new
      @read_waiter = TupleBag.new
      @take_waiter = TupleBag.new
      @notify_waiter = TupleBag.new
      @period = period
      @keeper = nil
    end

    def synchronize
      yield
    en

あとはMonitoroMixinのnew_condが書ければ良さそう。Rindaの使い方の場合、一つのtake/readを待つのは一つの実行主体だけなので、簡単なイベントを作って逃げることした。

module Rinda
  class Event
    def initialize
      @waiter = []
    end
    
    def wait
      @waiter << Fiber.current.method(:resume)
      Fiber.yield
    end

    def signal
      return if @waiter.empty? # これは起こらないはず。たぶん。
      @waiter.shift.call
    end
  end

  class TupleSpace
    def new_cond
      Event.new
    end
  end

忘れてたけど、notifyって操作があって(なんで追加したんだろう)がQueueを使ってるのでFiber用のQueueに交換。

module Bartender
  class Queue
    def initialize
      @reader = []
      @queue = []
    end

    def push(it)
      if @reader.empty?
        @queue << it
      else
        @reader.shift.call(it)
      end
    end
    
    def pop
      if @queue.empty?
        @reader << Fiber.current.method(:resume)
        Fiber.yield
      else
        @queue.shift
      end
    end
  end
end

module Rinda
  class NotifyTemplateEntry < TemplateEntry
    def initialize(place, event, tuple, expires=nil)
      ary = [event, Rinda::Template.new(tuple)]
      super(ary, expires)
      @queue = Bartender::Queue.new
      @done = false
    end
  end

動いたっぽい。でも持ってるテストはスレッドじゃないと試せないのばっかり。どうしよう。

gist.github.com

あわせて課金したい

今年もよろしくお願いします。