デッドロックを回避するにはどうすればよいですか?

coldplay.xixi
リリース: 2020-06-24 14:33:24
オリジナル
4510 人が閲覧しました

デッドロックを回避するにはどうすればよいですか?

デッドロックを回避する方法:

デッドロックは、2 つのスレッドが互いのリソースの解放を待機するときに発生します。 Python インタプリタはデッドロック状況を監視せず、積極的に対処策を講じないため、マルチスレッド プログラミングを実行する場合はデッドロックを回避するための措置を講じる必要があります。

デッドロックが発生すると、プログラム全体で例外も生成されず、プロンプトも表示されませんが、すべてのスレッドがブロックされ、続行できなくなります。

デッドロックは非常に発生しやすく、特にシステム内に複数の同期モニターがある場合、次のプログラムはデッドロックを引き起こします:

import threading
import time
class A:
    def __init__(self):
        self.lock = threading.RLock()
    def foo(self, b):
        try:
            self.lock.acquire()
            print("当前线程名: " + threading.current_thread().name\
                + " 进入了A实例的foo()方法" )     # ①
            time.sleep(0.2)
            print("当前线程名: " + threading.current_thread().name\
                + " 企图调用B实例的last()方法")   # ③
            b.last()
        finally:
            self.lock.release()
    def last(self):
        try:
            self.lock.acquire()
            print("进入了A类的last()方法内部")
        finally:
            self.lock.release()
class B:
    def __init__(self):
        self.lock = threading.RLock()
    def bar(self, a):
        try:
            self.lock.acquire()
            print("当前线程名: " + threading.current_thread().name\
                + " 进入了B实例的bar()方法" )   # ②
            time.sleep(0.2)
            print("当前线程名: " + threading.current_thread().name\
                + " 企图调用A实例的last()方法")  # ④
            a.last()
        finally:
            self.lock.release()
    def last(self):
        try:
            self.lock.acquire()
            print("进入了B类的last()方法内部")
        finally:
            self.lock.release()
a = A()
b = B()
def init():
    threading.current_thread().name = "主线程"
    # 调用a对象的foo()方法
    a.foo(b)
    print("进入了主线程之后")
def action():
    threading.current_thread().name = "副线程"
    # 调用b对象的bar()方法
    b.bar(a)
    print("进入了副线程之后")
# 以action为target启动新线程
threading.Thread(target=action).start()
# 调用init()函数
init()
ログイン後にコピー

上記のプログラムを実行すると、表示される効果を確認してください。図 1 にあります。

デッドロックを回避するにはどうすればよいですか?

図 1 デッドロック効果

図 1 からわかるように、プログラムは下向きに実行することも、異常をスローすることもできません。 「行き詰まり」。その理由は、上記のプログラムのオブジェクト A とオブジェクト B のメソッドが両方ともスレッドセーフなメソッドであるためです。

プログラム内では 2 つのスレッドが実行されています。セカンダリ スレッドのスレッド実行本体は action() 関数で、メイン スレッドのスレッド実行本体は init() 関数です (メイン プログラムの呼び出しinit() 関数)。 action() 関数では、B オブジェクトが bar() メソッドを呼び出し、init() 関数では、A オブジェクトが foo() メソッドを呼び出します。

図 1 は、action() 関数が最初に実行され、B オブジェクトの bar() メソッドを呼び出すことを示しています。bar() メソッドに入る前に、スレッドは B オブジェクトの Lock をロックします (プログラムが 2 番のコードまで実行され、セカンダリ スレッドが 0.2 秒間一時停止します); CPU は別のスレッドの実行に切り替え、A オブジェクトに foo() メソッドを実行させるため、メイン スレッドが foo( foo() メソッドに入る前に、このスレッドはオブジェクト A の Lock をロックします (プログラムがコード①を実行すると、メインスレッドも 0.2 秒停止します)。

次に、セカンダリ スレッドが最初に起動し、コード ④ に到達するまで下方向に実行を続け、A オブジェクトの last() メソッドを呼び出すことを期待します (このメソッドを実行する前に、A オブジェクトの Lock最初にロックする必要があります) が、この時点ではメイン スレッドが A オブジェクトのロックを維持しているため、セカンダリ スレッドはブロックされます。

メインスレッドは次に起動し、B オブジェクトの last() メソッドを呼び出すコード ③ に到達するまで下方向に実行を続ける必要があります (このメソッドを実行する前に、B オブジェクトは最初に Lock されている必要があります) ) ですが、この時点ではセカンダリ スレッドは B オブジェクトのロックを解放しません。

この時点で、メイン スレッドはオブジェクト A のロックを保持してオブジェクト B がロックされるのを待機し、セカンダリ スレッドはオブジェクト B のロックを保持してオブジェクト A がロックされるのを待機しているように見えます。 2 つのスレッドは互いに待機し、ロックが先に解放されるため、デッドロックが発生します。

プログラムでデッドロックが発生してはなりません。プログラムを作成するときは、デッドロックを回避するように努める必要があります。 デッドロックの問題を解決するには、以下の一般的な方法があります:

  1. 複数のロックを避けてください。同じスレッド上で複数のロックをロックしないようにしてください。例えば、上記のデッドロックプログラムでは、メインスレッドは2つのオブジェクトAとBのLockをロックする必要があり、セカンダリスレッドも2つのオブジェクトAとBのLockをロックする必要があり、デッドロックの危険が潜んでいます。

  2. のロック シーケンスは同じです。複数のスレッドが複数のロックをロックする必要がある場合は、同じ順序でロックを要求するようにする必要があります。たとえば、上記のデッドロック プログラムでは、メイン スレッドは最初にオブジェクト A のロックをロックし、次にオブジェクト B のロックをロックしますが、セカンダリ スレッドは最初にオブジェクト B のロックをロックし、次にオブジェクト A のロックをロックします。このロック シーケンスにより、ネストされたロックが簡単に形成され、デッドロックが発生する可能性があります。この問題は、メインスレッドとセカンダリスレッドが同じ順序でロックすれば回避できます。

  3. #タイミング ロックを使用します。プログラムは、ロックするためにacquire()メソッドを呼び出すときにタイムアウト・パラメータを指定できます。このパラメータは、デッドロックのロックを解除できるように、タイムアウト秒後にロックが自動的に解放されることを指定します。

  4. デッドロックの検出。デッドロック検出は、アルゴリズム メカニズムに依存するデッドロック防止メカニズムであり、主に順次ロックが不可能で時間指定ロックが使用できないシナリオを対象としています。

以上がデッドロックを回避するにはどうすればよいですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

関連ラベル:
ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート