ホームページ  >  記事  >  バックエンド開発  >  Python マルチスレッド プログラミング 3: ミューテックス ロックを使用してスレッドを同期する

Python マルチスレッド プログラミング 3: ミューテックス ロックを使用してスレッドを同期する

高洛峰
高洛峰オリジナル
2016-10-18 11:33:201232ブラウズ

質問です

前のセクションの例では、各スレッドは互いに独立しており、相互に関係はありません。ここで例を想定します。グローバル カウント num があり、各スレッドはこのグローバル カウントを取得し、num に基づいて何らかの処理を実行し、その後 num に 1 を加算します。次のようなコードを書くのは簡単です:

# encoding: UTF-8
import threading
import time
  
class MyThread(threading.Thread):
    def run(self):
        global num
        time.sleep(1)
        num = num+1
        msg = self.name+' set num to '+str(num)
        print msg
num = 0
def test():
    for i in range(5):
        t = MyThread()
        t.start()
if __name__ == '__main__':
    test()

しかし、実行結果は正しくありません:


Thread-5 set num to 2

Thread-3 set num to 3

Thread-2 set num to 5

Thread-1 set num to 5

Thread-4 set num to 4


問題の理由は、同じリソースへの複数のスレッドのアクセスが制御されていないため、データが損傷し、スレッド操作の結果は予測できません。この現象は「スレッドアンセーフ」と呼ばれます。

ミューテックス ロックの同期

上記の例は、マルチスレッド プログラミングの最も一般的な問題、つまりデータ共有につながります。ある共有データを複数のスレッドで変更する場合、同期制御が必要となります。

スレッド同期により、複数のスレッドが競合するリソースに安全にアクセスできるようになります。最も簡単な同期メカニズムは、ミューテックス ロックを導入することです。ミューテックスは、ロック/ロック解除という状態をリソースに導入します。スレッドが共有データを変更したい場合は、まずそのリソースをロックする必要があり、その時点でリソースのステータスは「ロック」されており、スレッドがリソースを解放してリソースのステータスを「」に変更するまで、他のスレッドはそれを変更できません。ロックが解除されました」と表示された場合、他のスレッドはリソースを再度ロックできます。ミューテックス ロックは、一度に 1 つのスレッドだけが書き込み操作を実行することを保証するため、マルチスレッド状況でのデータの正確性が保証されます。

Lock クラスはスレッド モジュールで定義されており、ロックを簡単に処理できます:

#Create lock

mutex = threading.Lock()

#Lock

mutex.acquire([timeout])

#Release

mutex.release()

このうち、lockメソッドacquireはタイムアウト付きのパラメータtimeoutをオプションで持つことができます。タイムアウトが設定されている場合、戻り値を使用してタイムアウト後にロックが取得されたかどうかを判断できるため、他の処理を実行できます。

ミューテックスを使用して上記の例を実装するコードは次のとおりです:

import threading
import time
  
class MyThread(threading.Thread):
    def run(self):
        global num
        time.sleep(1)
  
        if mutex.acquire(1): 
            num = num+1
            msg = self.name+' set num to '+str(num)
            print msg
            mutex.release()
num = 0
mutex = threading.Lock()
def test():
    for i in range(5):
        t = MyThread()
        t.start()
if __name__ == '__main__':
    test()

実行結果:


Thread-3 set num to 1

Thread-4 set num to 2

Thread-5 set num to 3

Thread-2 set num to 4

Thread-1 set num to 5

ミューテックス ロックを追加した後の実行結果が期待どおりであることがわかります。

同期ブロッキング

スレッドがロックのacquire()メソッドを呼び出してロックを取得すると、ロックは「ロック」状態になります。一度に 1 つのスレッドだけがロックを取得できます。このときに別のスレッドがロックを取得しようとすると、そのスレッドは「ブロック」されます。これを「同期ブロック」と呼びます (マルチスレッドの基本概念を参照)。

ロックを所有するスレッドがロックの release() メソッドを呼び出してロックを解放するまで、ロックは「ロック解除」状態になります。スレッド スケジューラは、同期ブロッキング状態にあるスレッドの 1 つを選択してロックを取得し、そのスレッドを実行状態にします。

ミューテックス ロックの最も基本的な内容は次のとおりです。次のセクションでは、リエントラント ロック (RLock) とデッドロックの問題について説明します。


声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。