Ruby の Monitor
Ruby には Monitor というクラスがあるんだけど、よく見るわりに Mutex との違いをよくわかっていなかった。 たまたま Java Concurrency in Practice を読んでいたら 2.3.2 Reentrancy で同じような概念の話が出てきて、少しわかった気がするのでそのメモ。

- 作者: Brian Goetz,Tim Peierls,Joshua Bloch,Joseph Bowbeer,David Holmes,Doug Lea
- 出版社/メーカー: Addison-Wesley Professional
- 発売日: 2006/05/09
- メディア: ペーパーバック
- 購入: 7人 クリック: 14回
- この商品を含むブログ (22件) を見る
Monitor とは
Ruby の Monitor は何度も lock 出来る Mutex とドキュメントに書いてある。
特になんの意味もない例だけど以下のようにロック中にさらにロックできる(もちろん同じスレッド内で)。
もしこのコードを Mutex を使用して m = Mutex.new
とした場合、2回めの m
のロックする部分(m.synchronize
)でデッドロックが発生するが Monitor を使用すると発生しない。
m = Monitor.new m.synchronize do m.synchronize do # your code end end
使い所
たぶん使い所は、すでにあるコードを組みわせてアトミックな処理をするところ。
下のようなコードのような感じ。もともと Nanika
クラスに sugoi
というスレッドセーフなメソッドがあったとする。
この時、メソッド内でアトミックに sugoi
を2回呼び出す ultra_sugoi
というメソッドを新たに追加しようとしたときに Monitor が使えそう。
Monitor ではなく Mutex を使用すると、ultra_sugoi
内でロックを取ってから sugoi
のメッソド呼び出しが発生して、 sugoi
内で またロックを取りに行きデッドロックが発生する。
しかし、Montior を使用すると何度でもロックが成功するので、 sugoi
をアトミックに2回呼び出せる。
class Nanika def initialize @monitor = Monitor.new @sugoi_value = 0 end def sugoi @monitor.synchronize do @sugoi_value += 1 end end def ultra_sugoi @monitor.synchronize do sugoi sugoi end end end nanika = Nanika.new [*1..2].map { Thread.new do nanika.ultra_sugoi end }.each(&:join)
その他
javaの本では reentrant という言葉で説明されていた。
reentrancy とは
Reentrancy means that locks are acquired on a per-thread rather than per-invocation basis.
リエントラント性とは、呼び出し単位ではなくスレッド単位でロックが取得される。
Lock with reentrant
同じスレッドであれば、何度でもロックを取得できる ロックしたスレッドとそのスレッド内でのロック保持数を記録しておく。Ruby の Monitor。
Lock without reentrant
呼び出し(処理)単位でロックを取っているので、同じスレッドであっても再度ロックを取れない。 単純にロックされているかどうかだけを見る。Ruby の Mutex。
RubyはGILが
そうね