TechNote by 古賀信哉

技術情報のメモ書き(備忘録)

monitorとsemaphore

2005-04-29 18:31:56 | マルチスレッド
暫くぶりで、まとまった量のコードをJavaで書いたのですが、Javaの排他制御機構は、それほど悪くないなという感想が残りました。この点、以前とは、少し印象が変わったところです。

C/C++でマルチスレッドのコードを書くと、セマフォやロック(mutex)を使った排他制御が基本になって、Javaが基本とするmonitorを、いわばバラした形で使うわけですが、プログラミングのうえで「間違いをしづらくするための制約」という観点からすると、Javaのmonitorは、悪くない力を与えているなと思い直しました。

たとえば、producer/consumer型のマルチスレッドプログラミングを行う場合です。カウンティング・セマフォを使えば、consumerのキューが空になった時の待ち動作と、producerがキューへ処理対象を投入した際の通知動作が、セマフォだけで実現できてしまうわけなので、Javaのmonitorは、大げさ過ぎて邪魔に思えます。しかし、キューの実装によっては、キュー要素の取り出し(dequeue)と投入(enqueue)がthread safeではなく、それらに対する排他制御が必要になります。

さらに、producerとconsumerが、どちらも処理を終えた場合に全体動作を完了させる、といった仕組みを入れようとすると、特に、consumerに複数のスレッドを割り当てる場合には、それらに付随した共有情報を管理しなければいけません。

そういう場合には、Javaのmonitorを使う方が、融通が利かない分、却って詳細設計をやり易いなと感じました。つまり、java.lang.Object.notify[All]()は、それを呼び出した時点で、同じオブジェクトに対するjava.lang.Object.wait()を呼び出して待ち状態に入っているスレッドがないと、何の効果も生まないため、カウンティングセマフォの場合に比べると、待ち動作と通知の実現において、余分な情報を管理しなければいけません。同期のさせ方が単純な場合には、Javaのmonitorは、うざったいだけなのですが、多少なりとも込み入ってくると、むしろ、使い方をきちんと考えなければいけないぶん、Javaのmonitorの方が使い良い局面があるわけです。

Javaの言語仕様では、monitorを基本に据えた同期機構について、フレームワークという呼び方をしていますが、確かに、そうだなと思いました。

以前、マルチプラットフォーム用のスレッドライブラリを仕事で作った際、C++のライブラリAPIとして、java.lang.Threadに似たインタフェースを持つクラスと、入れ子ロックが可能なロックのクラス、および、pthreadsで言うconditional variableや、Win32 APIで言うeventのような待ち動作用のクラスを作ったのですが、今回の仕事を終えてみて、Javaのsynchronized節のような書き方のできる、monitorのフレームワークがあると、より良い局面があるなと思い直しました。そのライブラリを作った当時は、Javaのmonitorなんて、うざったいだけだと考えていたのです。

そういえば、AppleがXCodeに入れている版のObjective-Cだか、純正gccがサポートしているObjective-Cだかで、Javaのと似た構文で同期や例外処理を書ける糖衣構文(syntax sugar)が導入されたようですが、それもまた、悪いことではないなと思います。