同期プリミティブ
****************

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

======================================================================

asyncio の同期プリミティブは "threading" モジュールのそれと類似するよ
うにデザインされていますが、2つの重要な注意事項があります:

* asyncio の同期プリミティブはスレッドセーフではありません。従って OS
  スレッドの同期に使うべきではありません (代わりに "threading" を使っ
  てください);

* 同期プリミティブのメソッドは *timeout* 引数を受け付けません; タイム
  アウトを伴う操作を実行するには "asyncio.wait_for()" 関数を使ってくだ
  さい。

asyncio モジュールは以下の基本的な同期プリミティブを持っています:

* "Lock"

* "Event"

* "Condition"

* "Semaphore"

* "BoundedSemaphore"

======================================================================


Lock
====

class asyncio.Lock

   asyncio タスクのためのミューテックスロックを実装しています。スレッ
   ドセーフではありません。

   asyncio ロックは、共有リソースに対する排他的なアクセスを保証するた
   めに使うことができます。

   Lock の望ましい使用方法は、 "async with" 文と組み合わせて使うことで
   す:

      lock = asyncio.Lock()

      # ... later
      async with lock:
          # access shared state

   これは以下のコードと等価です:

      lock = asyncio.Lock()

      # ... later
      await lock.acquire()
      try:
          # access shared state
      finally:
          lock.release()

   バージョン 3.10 で変更: *loop* パラメータが削除されました。

   coroutine acquire()

      ロックを獲得します。

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

      複数のコルーチンが "acquire()" メソッドによりロックの解除を待ち
      受けている場合、最終的にただひとつのコルーチンが実行されます。

      ロックの獲得は *公平* です: すなわちロックを獲得して実行されるコ
      ルーチンは、最初にロックの待ち受けを開始したコルーチンです。

   release()

      ロックを解放します。

      ロックが *ロック状態* の場合、 ロックを *解除状態* にしてリター
      ンします。

      ロックが *解除状態* の場合、 "RuntimeError" 例外が送出されます。

   locked()

      *ロック状態* の場合に "True" を返します。


Event
=====

class asyncio.Event

   イベントオブジェクトです。スレッドセーフではありません。

   asyncio イベントは、複数の asyncio タスクに対して何らかのイベントが
   発生したことを通知するために使うことができます。

   Event オブジェクトは内部フラグを管理します。フラグの値は "set()" メ
   ソッドにより *true* に、また "clear()" メソッドにより *false* に設
   定することができます。 "wait()" メソッドはフラグが *true* になるま
   で処理をブロックします。フラグの初期値は *false* です。

   バージョン 3.10 で変更: *loop* パラメータが削除されました。

   以下はプログラム例です:

      async def waiter(event):
          print('waiting for it ...')
          await event.wait()
          print('... got it!')

      async def main():
          # Create an Event object.
          event = asyncio.Event()

          # Spawn a Task to wait until 'event' is set.
          waiter_task = asyncio.create_task(waiter(event))

          # Sleep for 1 second and set the event.
          await asyncio.sleep(1)
          event.set()

          # Wait until the waiter task is finished.
          await waiter_task

      asyncio.run(main())

   coroutine wait()

      イベントがセットされるまで待機します。

      イベントがセットされると、即座に "True" を返します。 そうでなけ
      れば、他のタスクが "set()" メソッドを呼び出すまで処理をブロック
      します。

   set()

      イベントをセットします。

      イベントがセットされるまで待機している全てのタスクは、即座に通知
      を受けて実行を再開します。

   clear()

      イベントをクリア (アンセット) します

      "wait()" メソッドで待ち受けを行うタスクは "set()" メソッドが再度
      呼び出されるまで処理をブロックします。

   is_set()

      イベントがセットされている場合 "True" を返します。


Condition
=========

class asyncio.Condition(lock=None)

   条件変数オブジェクトです。スレッドセーフではありません。

   asyncio 条件プリミティブは何らかのイベントが発生するのを待ち受け、
   そのイベントを契機として共有リソースへの排他的なアクセスを得るため
   に利用することができます。

   本質的に、 Condition オブジェクトは "Event" と a "Lock" の2つのクラ
   スの機能を組み合わせたものです。複数の Condition オブジェクトが単一
   の Lock を共有することでができます。これにより、共有リソースのそれ
   ぞれの状態に関連する異なるタスクの間で、そのリソースへの排他的アク
   セスを調整することが可能になります。

   オプション引数 *lock* は "Lock" または "None" でなければなりません
   。後者の場合自動的に新しい Lock オブジェクトが生成されます。

   バージョン 3.10 で変更: *loop* パラメータが削除されました。

   Condition の望ましい使用方法は "async with" 文と組み合わせて使うこ
   とです:

      cond = asyncio.Condition()

      # ... later
      async with cond:
          await cond.wait()

   これは以下のコードと等価です:

      cond = asyncio.Condition()

      # ... later
      await cond.acquire()
      try:
          await cond.wait()
      finally:
          cond.release()

   coroutine acquire()

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

      このメソッドは下層のロックが  *解除される* まで待機し、ロックを
      *ロック状態* に変更して "True" を返します。

   notify(n=1)

      この条件を待ち受けている最大で *n* 個のタスク (*n* のデフォルト
      値は 1) を起動します。待ち受けているタスクがいない場合、このメソ
      ッドは何もしません。

      このメソッドが呼び出される前にロックを獲得しておかなければなりま
      せん。また、メソッド呼び出し後速やかにロックを解除しなければなり
      ません。 *解除された* ロックとと共に呼び出された場合、
      "RuntimeError" 例外が送出されます。

   locked()

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

   notify_all()

      この条件を待ち受けている全てのタスクを起動します。

      このメソッドは "notify()" と同じように振る舞いますが、待ち受けて
      いる全てのタスクを起動します。

      このメソッドが呼び出される前にロックを獲得しておかなければなりま
      せん。また、メソッド呼び出し後速やかにロックを解除しなければなり
      ません。 *解除された* ロックとと共に呼び出された場合、
      "RuntimeError" 例外が送出されます。

   release()

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

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

   coroutine wait()

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

      このメソッドが呼び出された時点で呼び出し元のタスクがロックを獲得
      していない場合、 "RuntimeError" 例外が送出されます。

      このメソッドは下層のロックを解除し、その後 "notify()" または
      "notify_all()" の呼び出しによって起動されるまで処理をブロックし
      ます。いったん起動されると、  Condition は再びロックを獲得し、メ
      ソッドは "True" を返します。

   coroutine wait_for(predicate)

      引数 predicate の条件が *真* になるまで待機します。

      引数 predicate は戻り値が真偽地として解釈可能な呼び出し可能オブ
      ジェクトでなければなりません。 predicate の最終的な値が戻り値に
      なります。


Semaphore
=========

class asyncio.Semaphore(value=1)

   セマフォオブジェクトです。スレッドセーフではありません。

   セマフォは内部のカウンターを管理しています。カウンターは
   "acquire()" メソッドの呼び出しによって減算され、 "release()" メソッ
   ドの呼び出しによって加算されます。カウンターがゼロを下回ることはあ
   りません。 "acquire()" メソッドが呼び出された時にカウンターがゼロに
   なっていると、セマフォは処理をブロックし、他のタスクが "release()"
   メソッドを呼び出すまで待機します。

   オプション引数 *value* は内部カウンターの初期値を与えます (デフォル
   トは "1" です)。 指定された値が "0" より小さい場合、 "ValueError"
   例外が送出されます。

   バージョン 3.10 で変更: *loop* パラメータが削除されました。

   セマフォの望ましい使用方法は、 "async with" 文と組み合わせて使うこ
   とです:

      sem = asyncio.Semaphore(10)

      # ... later
      async with sem:
          # work with shared resource

   これは以下のコードと等価です:

      sem = asyncio.Semaphore(10)

      # ... later
      await sem.acquire()
      try:
          # work with shared resource
      finally:
          sem.release()

   coroutine acquire()

      セマフォを獲得します。

      内部カウンターがゼロより大きい場合、カウンターを1つ減算して即座
      に "True" を返します。内部カウンターがゼロの場合、 "release()"
      が呼び出されるまで待機してから "True" を返します。

   locked()

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

   release()

      セマフォを解放し、内部カウンターを1つ加算します。セマフォ待ちを
      しているタスクを起動する可能性があります。

      "BoundedSemaphore" と異なり、 "Semaphore" は "release()" を
      "acquire()" よりも多く呼び出すことを許容します。


BoundedSemaphore
================

class asyncio.BoundedSemaphore(value=1)

   有限セマフォオブジェクトです。スレッドセーフではありません。

   有限セマフォは "Semaphore" の一種で、 "release()" メソッドの呼び出
   しにより内部カウンターが *初期値* よりも増加してしまう場合は
   "ValueError" 例外を送出します。

   バージョン 3.10 で変更: *loop* パラメータが削除されました。

======================================================================

バージョン 3.9 で変更: "await lock" や "yield from lock" およびそれら
と "with" 文との組み合わせ (すなわち "with await lock" や "with (yield
from lock)") によるロックの獲得は削除されました。代わりに "async with
lock" を使ってください。
