けいじゅ@いそうろう.日本ラショナルです.

In [ruby-list :03649 ] the message: "[ruby-list:3649] [Q] How to use
Synchronizer? ", on Aug/10 21:31(JST) shugo / po.aianet.ne.jp (maeda
shugo) writes:

>前田です。
>
>Mutexを使うと
>
>$m = Mutex.new
>def foo
>   $m.synchronize do
>      print "foo\n"
>   end
>end
>3.times do
>   $m.synchronize do
>      foo
>   end
>end
>
>のようなのがうまく動きませんよね?

ですね.

>Mutexの代りにSynchronizerを使ってみたらうまくいったのですが、
>Synchronizerではこういった場合の動作も保証されているのでしょうか?

保証されています. ただし, カウントを数えているのでlockの数だけunlockを
行わないとlockが解除されません.

>それと、modeの指定の意味がわからないのですが、どうやって使うもの
>なのでしょう?

そうですね. 説明って全然ないですよね...

Syncronizerは(カウント付)2-phase lockを採用しています. 

mode:
  :UN    ロックの解除
  :SH    共有ロック
  :EX    排他ロック

:EXがMutexのロックと同じモードです. このロックがかかっている時に, 他の
スレッドがロックしようとするとブロックされます. 排他ロックはwrite lock
ともいいます. 書き込み中に他のクライアント(スレッド)が読み/書きすると
危険ですよね.

:SHは共有ロックでflockのLOCK_SHと同じものだと思います. このロックがか
かっている時は, 以下の動作をします:

* 他のスレッドが共有ロックを行おうことはできる.
* 他のスレッドが排他ロックを行おうとすると, ブロックされる.

共有ロックは read lock とも呼ばれます. 読み込みの場合, 同時に複数のク
ライアント(スレッド)が読み込んでも安全ですが, 書き込みが行われると不整
合が発生する可能性があるのでwrite はblockされるようになっています.

普通の2-phase lockと違うところは, countがついているところなのですが:

カウントはどうなっているかというと, カウントは2種類あって
read-lock-countとwrite-lock-count があります. 動作はどうなっているかと
いうと以下の例を見て下さい::

R:  共有ロック(read-lock)
W:  排他ロック(write-lock)
Rn: 共有ロックカウント
Wn: 排他ロックカウント

case 1:
ロックの種類:R         R         R         UL        UL        UL
カウントの数:->(R1, W0)->(R2, W0)->(R3, W0)->(R2, W0)->(R1, W0)->(R0, W0)

という感じでロックを行うとカウントが増えて, アンロックするとカウントが
減ります.

case 2:
ロックの種類:W         W         W         UL        UL        UL
カウントの数:->(R0, W1)->(R0, W2)->(R0, W3)->(R0, W2)->(R0, W1)->(R0, W0)

排他ロックの場合も同じです. 問題なのが共有ロックと排他ロックが混在した
時です:

case 3:
ロックの種類: R       -> R      -> W      -> UL     -> UL     -> UL
カウントの数: (R1, W0)->(R2, W0)->(R2, W1)->(R2, W0)->(R1, W0)->(R0, W0)

write lockが行われた時点で, lockのモードが排他ロックにアップグレードさ
れます.

unlockは, ロックをかけた順番の逆順に解除されます. この場合, 1度めの
unlockで排他lockが解除され, 残り2回unlockを行うと共有ロックが解除され
ます.

あくまでも, ロックをかけた逆順番にロックが解除されるので, 注意が必要で
す. Synchronizer#syncを使っている限り問題はないと思いますが...

case 4:
ロックの種類: R       -> W      -> R      -> UL     -> UL     -> UL
カウントの数: (R1, W0)->(R1, W1)->(R1, W2)->(R1, W1)->(R1, W0)->(R0, W0)

排他ロックの後にかけたロックは, 常に排他ロックとなります.

この場合, 2度めのunlockで排他ロックが解除され, 3度めのunlockで共有ロッ
クが解除されます.

PS.
現在, Synchronizerをversion up中です. Mutex_mのような機能をつけようと
しています.

あと, case 3の注意事項がちょっと気になるので, unlockにモードもつけられ
るようにしたいと思います.

__
..........................................石塚 圭樹@日本ラショナル...
----------------------------------->> e-mail: keiju / bc.mbn.or.jp <<---