threading.Condition
Conditionという排他オブジェクトです。
import time import threading class MyThread(threading.Thread): lock = threading.Lock() def __init__(self, name, lifetime, condition): threading.Thread.__init__(self) self.lifetime = lifetime self.condition = condition def run(self): while not self.lifetime <= 0: self.lifetime -= 1 with self.lock: time.sleep(0.3) print threading.current_thread().getName(), "life is " , self.lifetime with self.condition: print threading.current_thread().getName(), "acquire" self.condition.notify() def main(): condition = threading.Condition(threading.Lock()) t1 = MyThread("t1", 5, condition) t2 = MyThread("t2", 5, condition) t1.start() t2.start() fact = 0 while fact < 5: with condition: condition.wait() if not t1.isAlive(): t1 = MyThread("t1_" + str(fact), 5, condition) t1.start() else: t2 = MyThread("t2_" + str(fact), 5, condition) t2.start() fact += 1 t1.join() t2.join() if __name__ == '__main__': main()
threading.Thread.isAliveはスレッドが走っているかどうかを返します。
acquire()とrelease()使わずにwithステートメントを使用しています。
condition.acquireが呼び出されると、そこで内部にあるLockオブジェクトで
condition.releaseが呼び出されるか、condition.waitが呼び出されるまでブロックします
waitで待機してるオブジェクトはcondition.notify、またはcondition.notifyAllで起こすことができます。
注意しなければいけないのはwaitもnotifyもロックを取得してる中で行わないと、例外RuntimeErrorが発生します。
notifyを呼び出し、releaseを呼び出したタイミングがwaitで待つオブジェクトが再開するタイミングです。
また内部のLockオブジェクトはコンストラクタで指定することができます。
class _Condition(_Verbose): def __init__(self, lock=None, verbose=None): _Verbose.__init__(self, verbose) if lock is None: lock = RLock() self.__lock = lock
デフォルトだとthreading.RLockオブジェクトです。
RLock(reentrant lock)はacquire/releaseをネストできるオブジェクトです。
acquireしてから更にacquireが呼び出せます。そしてacquireした分だけreleaseしないとロックは解放されません。