トップ «前の日記(2007-10-16) 最新 次の日記(2007-10-18)» 月表示 編集

日々の流転


2007-10-17 [長年日記]

λ. RubyでSTM

後で書く。

【2008-02-11 追記】 後で書こうと思いつつ、ずっと忘れていたが、ようやくまとめた。

<URL:http://www.tom.sfc.keio.ac.jp/~sakai/archives/ruby-stm-0.0.1.tar.gz>

使い方

STM.atomically{ ... } でトランザクションの実行。必要な条件が満たされていない場合などには、STM.retry で現在のトランザクションの再試行。STM.or(proc1, proc2, ...) は引数のProcを順番に試行して最初に成功した結果になる。全ての引数が再試行になったら、STM.or全体として再試行になる。

STM::Var が Haskell の TVar 相当で、トランザクションの対象となる「変数」。トランザクション中に、STM::Var.new(value) で作って、STM::Var#get, STM::Var#set(val) で読み書き。

STM::Array というのも用意してあって、こちらはトランザクションの対象となる「配列」。Rubyの配列で使える操作はほぼそのまま使える。

それから、STM::MVar が Haskell の TMVar 相当。

実装

シンプルな実装。

トランザクション中で最初に STM::Var を読み込んだときの値と、そのトランザクション中で更新した結果の値を、トランザクションのオブジェクトに記録。コミット時にはグローバルなロック*1をかけて、記録された値と現在の値に齟齬がないことを確認し、それから実際の STM::Var に対して書き込む。もし齟齬があった場合には最初からやり直し。

再試行が起こった場合には、それまでに読んだ変数に対してそのトランザクションを登録し、それらの変数に対して変更がコミットされるまで待つ。

他の実装

実装後に気づいたのだけど、<URL:http://www.atdot.net/~ko1/diary/200701.html#d25> で笹田さんも実装していた。 また、<URL:http://moonbase.rydia.net/mental/blog/programming/ruby-stm> というものもあるようだ。

Tags: ruby

*1 グローバルなロックをかけるよりは、CASやLL/SCを使いたかったけど、Rubyには無いしね。