Pythonのthreadモジュール

Pythonのthreadモジュール
スレッドの同期と、スレッドの使用例










スレッドの同期
Lockオブジェクト: lockオブジェクトの生成
Lockオブジェクト: lock状態の獲得
Lockオブジェクト: lock状態の開放
Lockオブジェクトの使用例: Lock_Object.py
スレッドの使用例: spawn_thread.py
スレッドの使用例: spawn_thread_exit.py
スレッドの使用例: thread_count.py
スレッドの使用例: thread_mutex.py
スレッドの使用例: thread_count_wait.py
Pythonのthreadモジュール
スレッドの同期




スレッドを使うとき、複数のスレッドが共有する資源(グローバル変数など)
にアクセスすることがあります。
このようなとき、適切にスレッドの同期を取らないと、正しく動作しないことが
あります。
Pythonには、同期を取るためのオブジェクトがいくつか用意されています。
以下にPythonの同期オブジェクトを示します。
Lockオブジェクトは、最も簡便な同期機構である。Lockオブジェク
トは、mutexや、binaryセマフォとも呼ばれている。
Pythonのthreadモジュール
Lockオブジェクト: lockオブジェクトの生成
mtx = allocate_lock()


新しいロックオブジェクトを返します。
ロックは初期状態としてアンロック状態です。
Pythonのthreadモジュール
Lockオブジェクト: lock状態の獲得
mtx.acquire([waitflag])




オプションの引数なしで使用すると、このメソッドは他のスレッドがロック
しているかどうかにかかわらずロックを獲得し、None を返します。
ただし他のスレッドがすでにロックしている場合には解除されるまで待っ
てからロックを獲得します (同時にロックを獲得できるスレッドはひとつだ
けであり、これこそがロックの存在理由です)。
整数の引数 waitflag を指定すると、その値によって動作が変わります。
引数が 0 のときは、待たずにすぐ獲得できる場合にだけロックを獲得し
ます。0 以外の値を与えると、先の例と同様、ロックの状態にかかわら
ず獲得をおこないます。
なお、引数を与えた場合、ロックを獲得すると True、できなかったときに
は False を返します。
Pythonのthreadモジュール
Lockオブジェクト: lock状態の開放
mtx.release()


ロックを解放します。
そのロックは既に獲得されたものでなければなりませ
んが、同じスレッドによって獲得されたものである必要
はありません。
Pythonのthreadモジュール
Lockオブジェクトの使用例 Lock_Object.py
# lock object
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() :
global n, lck
while 1:
if lck.acquire() == 0 : pass
else :
n -= 1
lck.release()
time.sleep(3)
thread.start_new_thread(fadd, ())
thread.start_new_thread(fdec, ())
while 1:
print n
time.sleep(2)
Lock_Object.py
Pythonのthreadモジュール
スレッドの使用例: spawn_thread.py


threadを次々と生成する.
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
while 1:
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
Pythonのthreadモジュール
スレッドの使用例: spawn_thread_exit.py

threadクラスを使うメリット: 明示的にスレッド処理を停止する exit()
メソッドが提供されている

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
while 1:
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
Pythonのthreadモジュール
スレッドの使用例: 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,)
time.sleep(1.0)
if __name__ == "__main__":
print "Test with", sys.argv[0]
parentThread()
Pythonのthreadモジュール
スレッドの使用例: 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,)
time.sleep(1)
if __name__ == "__main__":
print "Test with", sys.argv[0]
parentThread()
Pythonのthreadモジュール
スレッドの使用例: 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()