2013年6月30日日曜日

Objectクラスと同期プリミティブ その3

条件変数 (condition variable)

あるスレッドで変数を更新し、それを別のスレッドで待って処理を行うために Objectクラスのモニタ機構を用いることができる。
このモニタによって更新の通知と待ち合わせが行われる変数を条件変数と呼ぶ。

変数の更新を待つスレッドはつぎのように記述される。
 Object_lock(object);
 Object_wait(object, 0L);
 // objectに関連付けられた変数を読み出す
 Object_unlock(object);

Object_lockによりロックが行われると Object_waitにより更新されたことの通知を待つ。
この間一時的にロックは自動解除される。そうしないと、更新する側もロックを取得しようとするため、更新動作に入れなくなる。
重要なのは、再び waitを行っていたスレッドがロックを獲得した状態で Object_waitから復帰するということである。
Object_waitの 2つ目の引数は待ち時間の上限をミリ秒単位の long値で指定する。 0Lを指定した場合は通知が行われるまで無限に待ち続ける。
条件変数は任意の変数で構わないが、objectが Objectのサブクラスであれば、条件変数はそのクラスのメンバとするのが良い。
変数を読み書きする処理をそのクラスの関数にする事で処理の詳細を隠蔽し、併せてその関数の中でロックも行うようにすることができる。
ロック操作を利用者側に任せるのはロック漏れの原因となる。
変数を読み出している最中に更なる変数の更新が行われないようオブジェクトをロックしなければならない。

変数を更新するスレッドはつぎのように記述される。
 Object_lock(object);
 // objectに関連付けられた変数に書き込む
 Object_notify(object);
 Object_unlock(object);

Object_lockと Object_unlockで囲まれた中で変数を更新し、Object_notifyで objectで何かが起こることを待っているスレッドを再開させる。
最後に Object_unlockでロックを解放する。
Object_lockを行おうとしたときに、他のスレッドが変数に書き込み中だったり、読み出し中のものがあればそれらが完了するまで待たされる。
objectを待っているスレッドが複数あるとき、Object_notifyはその中の 1個のスレッドだけを再開させる。
どのスレッドが再開されるかは処理系の実装依存である。最初に待ち状態に入ったものが解除されることを期待するようなコードを書いてはならない。
objectを待っている複数のスレッド全てを再開させるには Object_notifyの変わりに Object_notifyAllを使用する。

なお、softiesプロジェクトでは Object_lockは必ずロックを獲得した状態で復帰する。
ロックが獲得できるかどうか試してみる tryLockの仕組みは提供していない。
他のスレッドから割り込まれてキャンセルされた場合例外をスローすることを検討されているが、現在のところ例外機構は実験段階であり、キャンセルは行われない。



アンタって少な目。 半分の整髪。