##
7.5.3 Condition オブジェクト

条件変数(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つだけ消費者スレッドを起こす必要があります。

class `Condition`( | [lock])

  もしlock引数を`None`以外で与えるならば、 `Lock`または`RLock`オブジェクトでなければならず、 それは基礎ロックとして使われます。 それ以外のとき、新しい`RLock`オブジェクトを作り基礎ロックとして 使われます。

`acquire`( | *args)

  基礎ロックを獲得します。 このメソッドは基礎ロックに関連するメソッドを呼出します。 返り値はそのメソッドからのものです。

`release`( | )

  基礎ロックを解放します。 このメソッドは基礎ロックに関連するメソッドを呼出します。 返り値はありません。

`wait`( | [timeout])

  通知を受ける(notify)あるいはタイムアウトするまで待ちます。 これは呼出しスレッドがロックを獲得しているときにだけ、呼出すことができます。

  このメソッドは基礎ロックを解放し、他のスレッドで同じ条件変数の `notify()`または`notifyAll()`呼出しによって起こされるまで、 あるいはタイムアウトするまでブロックします。 いったん起こされたりタイムアウトしたなら、ロックを再獲得して戻ります。

  timeout引数が`None`以外で与えられたとき、 それはタイムアウトを秒(またはその分数)で指定する浮動小数であるべきです。

  基礎ロックが`RLock`の場合、それが複数回再帰的に獲得さられたときに アンロックされないので`release()`メソッドを使っては解放されません。 代わりに、`RLock`クラスの内部インターフェースが使うことで、実際には 再帰的に複数回獲得されたときにアンロックします。 そして他の内部インターフェースはロックが再獲得されたときに、 再帰レベルを元に戻すことで使用されます。

`notify`( | )

  もし存在するなら、この条件を待っているスレッドを起こします。 これは呼出しスレッドがロックを獲得しているときにだけ、呼出すように しなければいけません。

  もし待っているスレッドがあるのなら、このメソッドは条件変数を 待っているスレッドのうちの1つを起こします。 もし待っているスレッドがないのなら、なにもしません。

  もし待っているスレッドがあるのなら、現在の実装ではまさしく1つの スレッドを起こします。 しかしこの振舞いに依存するのは安全ではありません。 将来、最適化された実装は1つ以上のスレッドを起こすかもしれません。

  Note: 起こされたスレッドは実際にロックを再獲得できるまで`wait()` 呼出しから戻りません。 `notify()`はロックを解放しないからです。

`notifyAll`( | )

  この条件を待っているすべてのスレッドを起こします。 このメソッドは`notify()`のように作用しますが、 1つではなくすべての待ちスレッドを起こします。