pythonでデッドロックの問題を解決します。


1.タイムアウト時間を追加:

fromthreading import Thread, Lock
importtime 
mutex1= Lock()  #        
mutex2= Lock()  #        

def fun1():
    while True:
        mutex1.acquire()
        print("  1    mutex1")
        time.sleep(0.1)
 
        result =mutex2.acquire(timeout=1)  # timeout  acquire        
        # result = mutex2.acquire(False)  #    
        if result:
            #    mutex2    
            print("  1    mutex2")
            print("  1 hello")
            mutex1.release()
            mutex2.release()
            break
        else:
            #    mutex2    
           mutex1.release()  #  mutex1  ,        
            time.sleep(0.1)

def fun2():
    mutex2.acquire()
    print("  2    mutex2")
    time.sleep(0.1)
    mutex1.acquire()
    print("  2    mutex1")
    print("  2 hi") 
    mutex1.release()
    mutex2.release()
2.付録-銀行家アルゴリズム(要求しないで理解すればいいです。)
背景知識
銀行家はどのように一定の数の資金を安全にいくつかの取引先に貸して、これらの取引先にお金を借りてやりたいことを完成することができます。同時に銀行家は全部の資金を回収して破産に至らないことができます。これは銀行家の問題です。この問題はオペレーティングシステムの資源配分の問題と非常に似ています。銀行家はオペレーティングシステムのように、クライアントが実行するプロセスのように、銀行家の資金はシステムの資源です。
問題の説明
銀行は一定量の資金を持っています。いくつかの顧客がローンを求めています。すべての顧客は最初から彼が必要とするローンの総額を表明しなければならない。お客様の融資総額が銀行の資金総数を超えない場合、銀行はお客様の要求を受け入れることができます。お客様のローンは毎回の資金単位(例えば1万RMBなど)で行われます。お客様は必要な全部の単位の金額を借りる前に待つかもしれません。
例えば、3つの取引先C 1、C 2、C 3があります。銀行家からの資金総額は10の資金単位です。C 1の取引先は9の各資金単位を借ります。C 2の取引先は3つの資金単位を借ります。C 3の取引先は8つの資金単位を借ります。合計20の資金単位です。ある時点の状態を図に示します。

a図の状態については、安全シーケンスの要求に従って、私達が選んだ最初の顧客はこの顧客の必要なローンが銀行家の現在の残りのお金より小さいです。C 2の顧客だけが満足できると見られています。C 2の顧客は1つの資金単位が必要で、銀行家が持っている2つの資金単位が必要です。そこで銀行家は1つの資金単位をC 2の顧客に貸します。仕事を完成させ、借りた3つの資金単位のお金を返済して、b図に入ります。同じように、銀行はC 3クライアントに4つの資金単位を貸して、仕事を完成させます。c図では、クライアントC 1だけが残っています。7つの資金単位が必要です。この時、銀行は8つの資金単位があります。だから、C 1も順調にお金を借りて仕事を完成します。最後に(図dを参照して)銀行家は全部の10の資金単位を回収して、元本を弁償しないことを保証します。じゃ、お客様のシーケンス{C 1,C 2,C 3}は安全なシーケンスです。このシーケンスでローンを借りれば、銀行家は安全です。そうでなければ、図bの状態で銀行が持っている4つの資金単位をC 1に貸したら、安全ではない状態になります。C 1、C 3は全部仕事ができません。銀行家の手にはお金がありません。システムが行き詰まり、銀行も投資を回収できません。
以上のように、銀行のアルゴリズムは現在の状態から出発して、一つ一つ安全なシーケンスで各取引先の誰がその仕事を完成することができるかを確認して、その後、仕事を完成してすべてのローンを返済すると仮定して、更に次の仕事ができる取引先を検査します。すべての取引先が仕事を完成できれば、安全なシーケンスを見つけられます。銀行家は安全です。
追加:python基礎-デッドロック、再帰ロック
デッド・ロック
いわゆるデッドロックとは、2つ以上のプロセスまたはスレッドが実行中にリソースを奪い合うことによって起こる、相互に待つ現象のことです。外力がないと、それらは進められなくなります。この時点でシステムはデッドロック状態またはシステムによってデッドロックが発生します。これらは常にお互いを待っているプロセスをデッドロックプロセスと呼びます。

from threading import Thread,Lock
import time
mutexA=Lock()
mutexB=Lock()
class MyThread(Thread):
    def run(self):
        self.func1()
        self.func2()
    def func1(self):
        mutexA.acquire()
        print('\033[41m%s   A \033[0m' %self.name)
        mutexB.acquire()
        print('\033[42m%s   B \033[0m' %self.name)
        mutexB.release()
        mutexA.release()
    def func2(self):
        mutexB.acquire()
        print('\033[43m%s   B \033[0m' %self.name)
        time.sleep(2)
        mutexA.acquire()
        print('\033[44m%s   A \033[0m' %self.name)
        mutexA.release()
        mutexB.release()
if __name__ == '__main__':
    for i in range(5):
        t=MyThread()
        t.start()
出力は以下の通りです
Thread-1はA錠を持ってきてください
Thread-1はB錠を持ってきてください
Thread-1はB錠を持ってきてください
Thread-2はA錠をもらいます
上記のコードはどのようにデッドロックが生まれたかを分析します。
5つのスレッドを起動して、run方法を実行して、もしthread 1が先にAロックを奪ったら、この時thread 1はAロックを解除していないで、続いてコードmutex B.acquireを実行して、Bロックを奪い取った時、他のスレッドとthread 1は奪い合いません。Fnc 2では、コードmutexB.acquire()を実行して、Bロックを奪ってから、スリープ状態に入ります。thread 1でFnc 1関数を実行して、ABロックを解除する時に、他のスレッドもAロックを奪い始めます。Fnc 1コードを実行します。Bロックを持っていますが、なぜ解放されませんでしたか?他のスレッドがないので、彼は寝ています。そして、Bロックを握っています。
再帰ロック
私たちはデッドロックを分析しましたが、pythonの中ではどうやってこのような再帰ロックを解決しますか?
Pythonでは、同じスレッド内で複数の同じリソースを要求することをサポートするために、pythonは、ロックRLockに再入力可能であることを提供する。
このRLockの内部はロックと一つのカウンタ変数を維持しています。counterはacquireの回数を記録しています。これによって資源が何度もrequireされることができます。スレッドのすべてのacquireがreleaseされるまで、他のスレッドはリソースを獲得することができます。上記の例では、ロックの代わりにRLockを使用すると、デッドロックは発生しません。

from threading import Thread,Lock,RLock
import time
mutexA=mutexB=RLock()
class MyThread(Thread):
    def run(self):
        self.f1()
        self.f2()
    def f1(self):
        mutexA.acquire()
        print('%s   A ' %self.name)
        mutexB.acquire()
        print('%s   B ' %self.name)
        mutexB.release()
        mutexA.release()
    def f2(self):
        mutexB.acquire()
        print('%s   B ' % self.name)
        time.sleep(0.1)
        mutexA.acquire()
        print('%s   A ' % self.name)
        mutexA.release()
        mutexB.release()
if __name__ == '__main__':
    for i in range(5):
        t=MyThread()
        t.start()
出力コードは以下の通りです。
E:\python\python_sdk\python.exe"E:/python/py_pro/3デッドロック現象と再帰ロック.py"
Thread-1はA錠を持ってきてください
Thread-1はB錠を持ってきてください
Thread-1はB錠を持ってきてください
Thread-1はA錠を持ってきてください
Thread-2はA錠をもらいます
Thread-2はB錠をもらいます
Thread-2はB錠をもらいます
Thread-2はA錠をもらいます
Thread-4はA錠を持ってきます
Thread-4はB錠を持ってきます
Thread-4はB錠を持ってきます
Thread-4はA錠を持ってきます
Thread-3はA錠を持ってきます
Thread-3はB錠を持ってきます
Thread-3はB錠を持ってきます
Thread-3はA錠を持ってきます
Thread-5はA錠を持ってきます
Thread-5はB錠を持ってきます
Thread-5はB錠を持ってきます
Thread-5はA錠を持ってきます
Process finished with exit code 0
または以下のような効果があります。
这里写图片描述
再帰的なロックのコードを説明します。
ロックAのために、Bは同じ再帰ロックであり、thread 1はA、Bロックを取得し、counterはacquireの回数を2回記録し、その後func 1で実行した後、再帰ロックを解除し、thread 1で再帰ロックを解除し、Fnc 1コードを実行した後、2つの可能性があります。func 1のタスクコードを実行します。
以上は個人の経験ですので、参考にしていただければと思います。間違いがあったり、完全に考えていないところがあれば、教えてください。