条件変数(condition variable)はつねにある種類のロックに関係しています; 明示的にロックを渡すこともできますし、 デフォルトによって暗黙で作成させることもできます。 (いくつかの条件変数が同じロックを共有しなければならない場合、 そのロックを明示的に渡すことができます。)
条件変数は、関連するロックと対応するメソッドを呼出すacquire()と release()を持っています。 加えてwait(),notify(),notifyAll()メソッドを 持っています。 呼出しスレッドがロックを獲得しているときにだけ、 この3つのメソッドを呼出すようにしなければいけません。
wait()メソッドはロックを解放し、他のスレッドで同じ条件変数を notify()またはnotifyAll()によって起こされるまで ブロックします。 いったん起こされるとそれはロックを再獲得して戻ります。 タイムアウトを指定することも可能です。
notify()メソッドは条件変数を待っているスレッドを1つ起こします。 notifyAll()メソッドは条件変数を待っている全てのスレッドを起こします。
Note: notify()とnotifyAll()はロックを解放しません。 これは次のことを意味します; スレッドが起こされたときwait()呼出しから直ちに戻らず、 notify()またはnotifyAll()を呼出したスレッドが 最終的にロックの所有権を譲ることで戻ります。
Tip: 条件変数を使う典型的なプログラミングスタイルは、 共有状態へ同期アクセスするためにロックを使います。 状態の特定の変更に興味のあるスレッドは、望む状態になるまでwait()を 繰り返し呼出します。 同時に、待ちスレッドのうちの1つが望む状態に対して、 状態を変更するスレッドがnotify()またはnotifyAll()を 呼出します。 例えば、以下のコードはバッファ容量に限界のない場合における 一般的な生産者-消費者問題です。
# Consume one item cv.acquire() while not an_item_is_available(): cv.wait() get_an_available_item() cv.release() # Produce one item cv.acquire() make_an_item_available() cv.notify() cv.release()
notify()とnotifyAll()の選択は、その状態が1つだけ あるいは複数の待ちスレッドに興味があるかによって考慮します。 例えば典型的な生産者-消費者問題で、バッファに1つのアイテムを加えたとき、 1つだけ消費者スレッドを起こす必要があります。
[lock]) |
None
以外で与えるならば、
LockまたはRLockオブジェクトでなければならず、
それは基礎ロックとして使われます。
それ以外のとき、新しいRLockオブジェクトを作り基礎ロックとして
使われます。
*args) |
) |
[timeout]) |
このメソッドは基礎ロックを解放し、他のスレッドで同じ条件変数の notify()またはnotifyAll()呼出しによって起こされるまで、 あるいはタイムアウトするまでブロックします。 いったん起こされたりタイムアウトしたなら、ロックを再獲得して戻ります。
timeout引数がNone
以外で与えられたとき、
それはタイムアウトを秒(またはその分数)で指定する浮動小数であるべきです。
基礎ロックがRLockの場合、それが複数回再帰的に獲得さられたときに アンロックされないのでrelease()メソッドを使っては解放されません。 代わりに、RLockクラスの内部インターフェースが使うことで、実際には 再帰的に複数回獲得されたときにアンロックします。 そして他の内部インターフェースはロックが再獲得されたときに、 再帰レベルを元に戻すことで使用されます。
) |
もし待っているスレッドがあるのなら、このメソッドは条件変数を 待っているスレッドのうちの1つを起こします。 もし待っているスレッドがないのなら、なにもしません。
もし待っているスレッドがあるのなら、現在の実装ではまさしく1つの スレッドを起こします。 しかしこの振舞いに依存するのは安全ではありません。 将来、最適化された実装は1つ以上のスレッドを起こすかもしれません。
Note: 起こされたスレッドは実際にロックを再獲得できるまでwait() 呼出しから戻りません。 notify()はロックを解放しないからです。
) |
ご意見やご指摘をお寄せになりたい方は、 このドキュメントについて... をご覧ください。