threading.Condition と、条件となる任意のオブジェクトをグローバル変数スコープにして
実現させます。
以下、サンプル
# -*- coding: utf-8 -*- from threading import Thread, Condition import time # 生成格納先リスト products = [] # 条件オブジェクトの作成 condition = Condition() # Producer スレッド class Producer(Thread): def run(self): global products global condition while True: with condition: if len(products) == 0: print('Producer: product append') products.append(1) condition.notify() time.sleep(2) # Consumer スレッド class Consumer(Thread): def run(self): global products global condition while True: with condition: if len(products) > 0: print('Consumer: product pop') products.pop(0) else: print('No product --> Wait') condition.wait() time.sleep(2) # スレッドの生成 producer_thread = Producer() consumer_thread = Consumer() # スレッドの開始 producer_thread.start() consumer_thread.start()
重要なのは、
Condition の ロックの取得(acquire) と解放(release) をする with ブロックの中で、
・notify や wait を行うこと。
→ with ブロックの中で wait になる条件を問い合わせる。
notify 通知 → wait()
結果
Producer: product append Consumer: product pop No product --> Wait Producer: product append Consumer: product pop Producer: product append Consumer: product pop Producer: product append Consumer: product pop Producer: product append Consumer: product pop No product --> Wait Producer: product append Consumer: product pop
notify() は、notify_all() の他に、notify(n) と通知する数=nを指定できるが、
マニュアルにはこう書いてある。
threading — Thread-based parallelism — Python 3.11.5 documentation
This method wakes up at most n of the threads waiting for the condition variable; it is a no-op if no threads are waiting. The current implementation wakes up exactly n threads, if at least n threads are waiting. However, it’s not safe to rely on this behavior. A future, optimized implementation may occasionally wake up more than n threads
待機しているスレッド n個までを起動できるとなっているが、
However, it’s not safe to rely on this behavior. A future, optimized implementation may occasionally wake up more than n threads
こう書かれていると躊躇します。
準備するCondition 毎に、wait() するスレッド、notify() するスレッドを管理することになります。