# 18.5.7. 同期プリミティブ

ソースコード: Lib/asyncio/locks.py

ロック:

- `Lock`

- `Event`

- `Condition`

セマフォ:

- `Semaphore`

- `BoundedSemaphore`

asyncio lock API は `threading` モジュールのクラス (`Lock`, `Event`, `Condition`, `Semaphore`, `BoundedSemaphore`) に近くなるよう設計されましたが、 timeout 引数はありません。 `asyncio.wait_for()` 関数を用いてタイムアオウト後にタスクをキャンセルすることが出来ます。

## 18.5.7.1. ロック

### 18.5.7.1.1. Lock

class `asyncio.``Lock`(*, loop=None)

  プリミティブなロックオブジェクトです。

  プリミティブロックは、ロックされたときに特定のコルーチンに所有されない同期プリミティブです。プリミティブロックは 'ロック状態' か 'アンロック状態' のどちらかの状態になります。

  これはアンロック状態で作成されます。基本メソッド `acquire()` と `release()` を持ちます。アンロック状態のとき、acquire() でロック状態に変更し直ちに返します。ロック状態のとき、acquire() は、他のコルーチンが release() を呼び出しアンロック状態に変更するまでブロックします。その後 acquire() はそれをロック状態にして返します。release() メソッドはロック状態のとき以外に呼び出してはなりません; これは状態をアンロック状態に変更して直ちに返します。アンロック状態でロック解除を行おうとすると `RuntimeError` が送出されます。

  1 個以上のコルーチンが acquire() でブロックされ、アンロック状態への変更を待っている場合、release() が呼び出されアンロック状態にリセットされたとき 1 個のコルーチンのみが開始されます; 最初に acquire() でプロックされたコルーチンが開始されます。

  `acquire()` はコルーチンであり、`yield from` で呼び出すべきです。

  ロックはコンテキストマネージャープロトコルもサポートしています。コンテキストマネージャー表現では、`(yield from lock)` のように使用します。

  このクラスは スレッド安全ではありません。

  使い方:

      lock = Lock()
      ...
      yield from lock
      try:
          ...
      finally:
          lock.release()

  コンテキストマネージャーでの使用法:

      lock = Lock()
      ...
      with (yield from lock):
          ...

  ロックオブジェクトはロック状態か否かを確認できます:

      if not lock.locked():
          yield from lock
      else:
          # lock is acquired
          ...

  `locked`()

    ロック状態のとき `True` を返します。

  coroutine `acquire`()

    ロックを獲得します。

    このメソッドはロックが解除されるまでブロックし、ロック状態に変更して `True` を返します。

    このメソッドは コルーチン です。

  `release`()

    ロックを解放します。

    ロックがロック状態のとき、アンロック状態にリセットして返します。他のコルーチンがプロックされロック解除を待っている場合、そのうちのひとつだけ開始されます。

    アンロック状態のロックに対して呼び出された場合、`RuntimeError` が送出されます。

    戻り値はありません。

### 18.5.7.1.2. Event

class `asyncio.``Event`(*, loop=None)

  `threading.Event` と等価で非同期な Event 実装です。

  イベントオブジェクトを実装するクラスです。イベントは `set()` メソッドで真に設定され、`clear()` メソッドで偽にリセットされるフラグを管理します。`wait()` メソッドはフラグが真になるまでブロックします。フラグの最初の値は偽です。

  このクラスは スレッド安全ではありません。

  `clear`()

    内部フラグを偽にリセットします。その後 `wait()` を呼んでいるコルーチンは `set()` が呼び出されて内部フラグが真に設定されるまでブロックします。

  `is_set`()

    内部フラグが真のとき `True` を返します。

  `set`()

    内部フラグを真に設定します。それを待っていたすべてのコルーチンが再開します。`wait()` を呼び出していたコルーチンへのブロックが解除されます。

  coroutine `wait`()

    内部フラグが真になるまでブロックします。

    入力時に内部フラグが真のとき直ちに `True` を返します。偽のときはコルーチンが `set()` を呼び出してフラグが真になるまでブロックし、真になった時点で `True` を返します。

    このメソッドは コルーチン です。

### 18.5.7.1.3. Condition

class `asyncio.``Condition`(lock=None, *, loop=None)

  `threading.Condition` と等価で非同期な Condition 実装です。

  このクラスは条件変数オブジェクトを実装しています。条件変数は 1 個以上のコルーチンが他のコルーチンから通知を受けるまで待機できるようにします。

  引数 lock に非 `None` が与えられた場合、それは `Lock` オブジェクトでなければなりません。これは下層のロックとして使用されます。与えられない場合、新しく `Lock` オブジェクトが作成されます。

  このクラスは スレッド安全ではありません。

  coroutine `acquire`()

    下層でのロックを獲得します。

    このメソッドはロックが解除されるまでブロックし、ロック状態に変更して `True` を返します。

    このメソッドは コルーチン です。

  `notify`(n=1)

    デフォルトでは、この条件を待機しているコルーチンがあればそれが再開されます。呼び出したコルーチンがこのロックを獲得していない状態でこのメソッドが呼び出されると `RuntimeError` が送出されます。

    このメソッドではこの条件変数を待機しているうち最大で n 個のコルーチンが再開されます; 待機しているコルーチンがなければ何もしません。

    注釈

    そのロックを獲得できるまで、再開されたコルーチンは実際には自身の `wait()` 呼び出しから復帰しません。`notify()` はロックの解除を行わないため、呼び出し元がそれを行わなければなりません。

  `locked`()

    下層のロックを獲得していれば `True` を返します。

  `notify_all`()

    この条件を待機しているすべてのコルーチンを再開します。このメソッドは `notify()` のように振る舞いますが、1 個ではなくすべてのコルーチンが再開されます。呼び出したコルーチンがロックを獲得していない状態でこのメソッドが呼び出されると `RuntimeError` が送出されます。

  `release`()

    下層のロックを解除します。

    ロックがロック状態のとき、アンロック状態にリセットされます。他にこのロックの解除を待機していたコルーチンが存在していた場合、そのうちの一つが再開されます。

    アンロック状態のロックに対して呼び出された場合、`RuntimeError` が送出されます。

    戻り値はありません。

  coroutine `wait`()

    通知を受けるまで待機します。

    呼び出したコルーチンがロックを獲得していない状態でこのメソッドが呼び出されると、`RuntimeError` が送出されます。

    このメソッドは下層のロックを解除し、その後それが他のコルーチンで同じ条件変数の `notify()` か `notify_all()` によって再開されるまでブロックします。再開されると、再びロックを獲得して `True` を返します。

    このメソッドは コルーチン です。

  coroutine `wait_for`(predicate)

    predicate が真になるまで待機します。

    predicate は呼び出し可能オブジェクトで、結果がブール値で解析できなければなりません。最終的な predicate の結果が戻り値となります。

    このメソッドは コルーチン です。

## 18.5.7.2. セマフォ

### 18.5.7.2.1. Semaphore

class `asyncio.``Semaphore`(value=1, *, loop=None)

  Semaphore 実装です。

  セマフォは `acquire()` の呼び出しで減算し、`release()` で加算する内部カウンターを管理します。カウンターは負数になることはありません; `acquire()` が呼び出されたときにセマフォがゼロであればブロックされ、他のコルーチンが `release()` を呼び出すまで待機します。

  セマフォはコンテキストマネージャープロトコルもサポートしています。

  任意の引数 value で内部カウンターの初期値を指定できます; デフォルトは `1` です。value に `0` 未満の値が指定されると、`ValueError` が送出されます。

  このクラスは スレッド安全ではありません。

  coroutine `acquire`()

    セマフォを獲得します。

    入力時内部カウンターがゼロより大きかった場合、1 減算され、直ちに `True` を返します。ゼロだった場合、ブロックされ、他のコルーチンが `release()` を呼び出してカウンター値が `0` より大きくなるまで待機し、獲得できると `True` を返します。

    このメソッドは コルーチン です。

  `locked`()

    セマフォを直ちに獲得できない場合 `True` を返します。

  `release`()

    セマフォを解放し、内部カウンターを 1 加算します。カウンター値がゼロで他のコルーチンが待機状態にあった場合、加算後そのコルーチンが再開されます。

### 18.5.7.2.2. BoundedSemaphore

class `asyncio.``BoundedSemaphore`(value=1, *, loop=None)

  `Semaphore` を継承した有限セマフォの実装です。

  `release()` 内でカウンター値が加算されて引数 value を超えると `ValueError` を送出します。