Ractor::TMVarを作った

Posted on November 30, 2020 , Tags: Ractor, Ractor::TMVar, Ractor::TVar, STM

Ractor::TVar に対応する TMVar がほしくなったので作った

TMVar

先日、Ractor で「食事する哲学者の問題」を解く という記事を書いた。その後、やはり TMVar に相当するものがほしい、という気持ちになった。
元々参考にしていた、STM で解く「食事する哲学者の問題」 - あどけない話 では TVar をそのまま使うのではなく、TMVar のほうを使っており、それに倣った形となる。
現状、ractor-tvar には retry に相当するものとしては、 raise Ractor::RetryTransaction するしかなく、例外処理で通常の分岐処理を行うのはあまり気持ちよくない、と感じたことも一因である。

takeTMVar, putTMVar

今回はとりあえず takeTMVar および putTMVar に相当する機能があれば十分と考えた。
これらのソースを参考にしながら実装をすすめる。

takeTMVar

実装は以下の通り。

TVar の値を読み込み、値が Nothing だったら retry, Just a だったら TVar を空にしてから a を返している。

putTMVar

実装は以下の通り。

今度は TVar の値が Nothing だったら値の書き込み、Just _ だったら retry となっている。

実装

Ruby での実装は以下のようにした。
(2020/12/01 追記) Ractor::TVar にあわせて以下のようなメソッド構成にしたが、あまりあわせる意味もないかと思い直し、Haskell の TMVar にあうように名前を変更した。ractor-tmvar 0.2.0 として push 済。

takeTMVarvalueputTMVarvalue= として、それぞれ同等の仕組みを実装した。
Haskell の TMVar では Maybe 型を使っているが、Ruby では使えない。そこで :RACTOR_TMVAR_BLANK というシンボルを用意して、それを Nothing 相当として動くようにした。 nilNothing 代わりにすることも考えたが、Ruby では nil を値として取得したいパターンもあるかもしれないという仮定の下、特別なシンボルを用意した。
こちらの実装を gem 化したものが ractor-tmvar となる。

「食事する賢者の問題」を Ractor::TMVar で解く

Ractor::TVar で解いた「食事する賢者の問題」を上記で実装した Ractor::TMVar で解くことにする。

Ractor::TVar で解くため、ループでのロック取得や、raise Ractor::RetryTransaction を使った retry で行っていた制御を Ractor::TMVar に隠蔽でき、スッキリしたコードになったと思う。

まとめ

Haskell の TMVar を参考にした、Ractor::TMVar を作った。
ソースコードは yoshitsugu/ractor-tmvar にある。
また、「食事する賢者の問題」を解いたリポジトリも更新した。