1. ホーム
  2. python

[解決済み] Pythonのスレッド化。スレッドをロックするにはどうしたらいいですか?

2022-03-01 13:21:26

質問

スレッドと並行処理の基本を理解しようとしています。2つのスレッドが1つの共有リソースに繰り返しアクセスしようとする簡単なケースを考えています。

コードです。

import threading

class Thread(threading.Thread):
    def __init__(self, t, *args):
        threading.Thread.__init__(self, target=t, args=args)
        self.start()
count = 0
lock = threading.Lock()

def increment():
    global count 
    lock.acquire()
    try:
        count += 1    
    finally:
        lock.release()
   
def bye():
    while True:
        increment()
        
def hello_there():
    while True:
        increment()

def main():    
    hello = Thread(hello_there)
    goodbye = Thread(bye)
    
    while True:
        print count

if __name__ == '__main__':
    main()

そこで、2つのスレッドがあり、両方ともカウンターをインクリメントしようとしています。もしスレッド 'A' が increment() は、その lock が成立し、Aが解除されるまでBがアクセスできないようにする。

を実行すると、そうでないことが明らかになります。ランダムなデータレース的な増分がすべて得られるのです。

ロックオブジェクトは具体的にどのように使われているのでしょうか?

さらに、スレッド関数の中にロックを入れてみましたが、まだうまくいきません。

解決方法は?

ロックを使っているうちに、もう少し処理を遅くしてブロックさせれば、かなり効果があることがわかります。重要なコードの一部をロックで囲むというのは、正しいアイデアでしたね。この例では、ロックが解除されるのをそれぞれがどのように待っているかを示すために、少し調整しています。

import threading
import time
import inspect

class Thread(threading.Thread):
    def __init__(self, t, *args):
        threading.Thread.__init__(self, target=t, args=args)
        self.start()

count = 0
lock = threading.Lock()

def incre():
    global count
    caller = inspect.getouterframes(inspect.currentframe())[1][3]
    print "Inside %s()" % caller
    print "Acquiring lock"
    with lock:
        print "Lock Acquired"
        count += 1  
        time.sleep(2)  

def bye():
    while count < 5:
        incre()

def hello_there():
    while count < 5:
        incre()

def main():    
    hello = Thread(hello_there)
    goodbye = Thread(bye)


if __name__ == '__main__':
    main()

サンプル出力です。

...
Inside hello_there()
Acquiring lock
Lock Acquired
Inside bye()
Acquiring lock
Lock Acquired
...