スレッドの同期と、スレッドの使用例 スレッドの同期 Lockオブジェクト: lockオブジェクトの生成 Lockオブジェクトの使用例: Lock_Object.py スレッドの使用例: spawn_thread.py スレッドの使用例: spawn_thread_exit.py スレッドの使用例: thread_count.py スレッドの使用例: thread_mutex.py スレッドの使用例: thread_count_wait.py
スレッドの同期 スレッドを使うとき、複数のスレッドが共有する資源(グローバル変数など)にアクセスすることがあります。 このようなとき、適切にスレッドの同期を取らないと、正しく動作しないことがあります。 Pythonには、同期を取るためのオブジェクトがいくつか用意されています。 以下にPythonの同期オブジェクトを示します。 Lockオブジェクトは、最も簡便な同期機構である。Lockオブジェクトは、mutexや、binaryセマフォとも呼ばれている。
Lockオブジェクト: lockオブジェクトの生成 mtx = allocate_lock() 新しいロックオブジェクトを返します。 ロックは初期状態としてアンロック状態です。
Lockオブジェクト: lock状態の獲得 mtx.acquire([waitflag]) オプションの引数なしで使用すると、このメソッドは他のスレッドがロックしているかどうかにかかわらずロックを獲得し、None を返します。 ただし他のスレッドがすでにロックしている場合には解除されるまで待ってからロックを獲得します (同時にロックを獲得できるスレッドはひとつだけであり、これこそがロックの存在理由です)。 整数の引数 waitflag を指定すると、その値によって動作が変わります。引数が 0 のときは、待たずにすぐ獲得できる場合にだけロックを獲得します。0 以外の値を与えると、先の例と同様、ロックの状態にかかわらず獲得をおこないます。 なお、引数を与えた場合、ロックを獲得すると True、できなかったときには False を返します。
Lockオブジェクト: lock状態の開放 mtx.release() ロックを解放します。 そのロックは既に獲得されたものでなければなりませんが、同じスレッドによって獲得されたものである必要はありません。
Lockオブジェクトの使用例 Lock_Object.py import thread, time n = 0 lck = thread.allocate_lock() def fadd() : global n, lck while 1: if lck.acquire() == 0 : pass else : n += 1 lck.release() time.sleep(2) def fdec() : n -= 1 time.sleep(3) thread.start_new_thread(fadd, ()) thread.start_new_thread(fdec, ()) print n Lock_Object.py
スレッドの使用例: spawn_thread.py mutexなし. import sys, time import thread def childThread(thread_id): while 1: print ' Hello from thread', thread_id time.sleep(1) def parentThread(): thread_id = 0 thread_id += 1 print ' Creating new thread' thread.start_new(childThread, (thread_id,)) print ' Destroy new thread' if raw_input() == 'q': break print "press 'q' to quit." if __name__ == "__main__": print "Test with", sys.argv[0] parentThread() spawn_thread.py
スレッドの使用例: spawn_thread_exit.py threadを次々と生成する. mutexなし. import sys, time import thread def childThread(thread_id): n = 0 while 1: print ' Hello from thread', thread_id, 'n', n time.sleep(3) n += 1 if n > 5: thread.exit() def parentThread(): thread_id = 0 thread_id += 1 print ' Creating new thread' thread.start_new(childThread, (thread_id,)) print ' Destroy new thread' if raw_input() == 'q': break print "press 'q' to quit." if __name__ == "__main__": print "Test with", sys.argv[0] parentThread() spawn_thread_exit.py
スレッドの使用例: thread_count.py threadを生成して, 自分のidとループindexを表示する. mutexなし. mutexなしなので, あるスレッドのループが完全に終了する前に, 他スレッドのループ出力が表示される可能性がある. import sys, time import thread def childThread(my_id, count): for i in range(0, count): time.sleep(1.0) print ' [my_id = %s] => %s' % (my_id, i) def parentThread(): for my_id in range(0, 10): print 'Create new thread [my_id = %s]' % (my_id,) thread.start_new(childThread, (my_id, 3)) print 'Destroy new thread [my_id = %s]' % (my_id,) if __name__ == "__main__": print "Test with", sys.argv[0] parentThread()
スレッドの使用例: thread_mutex.py threadを生成して, 自分のidとループindexを表示する. mutexあり. ループ開始時にmutexを取得しているので, あるスレッドのループ処理中に, 他スレッドがループ表示をすることがない. import sys import thread, time def childThread(my_id, count): mutex.acquire() for i in range(count): time.sleep(1) print ' [my_id = %s] => %s' % (my_id, i) mutex.release() def parentThread(): global mutex mutex = thread.allocate_lock() for my_id in range(10): print 'Creating new thread[my_id = %s]' % (my_id,) thread.start_new_thread(childThread, (my_id, 3)) print 'Destroy new thread[%s]' % (my_id,) if __name__ == "__main__": print "Test with", sys.argv[0] parentThread()
スレッドの使用例: thread_count_wait.py counter()関数のスレッドを作る. mutexあり. stdout用のmutex. すべてのスレッドが死ぬまで, 手動でブロックする. import sys, time import thread stdout_mutex = thread.allocate_lock() exit_mutexes = [0] * 10 def childThread(my_id, count): global exit_mutexes for i in range(count): stdout_mutex.acquire() print ' [my_id = %s] => %s' % (my_id, i) stdout_mutex.release() exit_mutexes[my_id] = 1 def parentThread(): for i in range(10): print 'Create new thread [my_id = %s]' % (my_id,) thread.start_new(counter, (i, 100)) print 'Destroy new thread [my_id = %s]' % (my_id,) while 0 in exit_mutexes: pass if __name__ == "__main__": print "Test with", sys.argv[0] parentThread()