什么是死鎖,如何防止死鎖(4種方法)

飛來科技  發布時間:2019-11-28 02:01:07

本文關鍵詞:多線程避免死鎖

多線程避免死鎖_c++線程死鎖_避免死鎖

我們先借助一個例子來預測,這個事例會引起死鎖,使得線程t1和線程t2互相期待他人傳遞鎖②、循環死鎖:線程a占有資源a,線程b占有資源b,線程c占有資源c,線程a申請占有資源b,同時規定占有資源b然后才釋放資源a,而線程b申請占有資源c,同時要求占有資源c然后才釋放資源b,線程c申請占有資源a,同時要求占有資源a然后才釋放資源c,這樣線程相互永久等待別人傳遞資源,這就是循環死鎖①、死鎖:線程a占有資源a,線程b占有資源b,線程a申請占有資源b,同時規定占有資源b然后才釋放資源a,而線程b申請占有資源a,同時要求占有資源a然后才釋放資源b,這樣兩個線程相互永久等待別人釋放資源,這就是死鎖

一旦出現死鎖,整個程序又不會發生任何異常,也不會給出任何提醒,只是所有線程都進入阻塞狀況,無法再次。

c++線程死鎖_多線程避免死鎖_避免死鎖

死鎖是很容易發生的,尤其是在平臺中發生多個同步監視器的狀況上,如下程序即將出現死鎖:

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 所示的效果。

c++線程死鎖_避免死鎖_多線程避免死鎖

線程死鎖效果

圖 1 死鎖效果

c++線程死鎖_多線程避免死鎖_避免死鎖

從圖 1 中可以看出,程序又能夠向下執行,也不會拋出任何異常,就經常“僵持”著。究其原因,是因為上面程序中 A 對象跟 B 對象的方式都是線程安全的技巧。

程序中有兩個線程執行,副線程的輪詢執行體是 action() 函數,主句柄的輪詢執行體是 init() 函數(主程序調用了 init() 函數)。其中在 action() 函數中讓 B 對象調用 bar() 方法,而在 init() 函數中讓 A 對象調用 foo() 方法。

避免死鎖_c++線程死鎖_多線程避免死鎖

4、當一個線程開始執行同步代碼塊時,并不意味著必須以不間斷的方法運行,進入同步代碼塊的輪詢可以執行thread.sleep()或執行thread.yield()方法,此時它并不釋放對象鎖,只是把運行的機會讓給其他的輪詢當一個線程開始執行同步代碼塊時,并不意味著必須以不間斷的方法運行,進入同步代碼塊的輪詢可以執行thread.sleep()或者執行thread.yield()方法,此時它并不釋放對象鎖,只是把運行的機會讓給其他的線程4、 當一個線程開始執行同步代碼塊時,并不意味著必須以不間斷的方法運行,進入同步代碼塊的輪詢可以執行thread.sleep()或者執行thread.yield()方法,此時它并不釋放對象鎖,只是把運行的機會讓給其他的線程

接下來副線程會先醒過來,繼續往下執行,直到執行至 ④ 號代碼處希望調用 A 對象的 last() 方法(在執行該方式之前,必須先對 A 對象的 Lock 加鎖),但這時主線程正保持著 A 對象的 Lock 的鎖定,所以副線程被阻塞。

調用object.wait()時,線程先應獲取這個對象的對象鎖,當前線程需要在鎖對象維持同步,把當前線程添加至等待隊列中,隨后另一線程可以同步同一個對象鎖來讀取object.notify(),這樣將激活原本期待中的線程,然后釋放該鎖 wait是object類的方式,對此對象讀取wait方法避免本句柄放棄對象鎖,進入期待此對象的等待鎖定池,只有對于此對象發出notify方法(或notifyall)后本線程才開啟對象鎖定池準備拿到對象鎖開啟運行狀況wait是object類的方式,對此對象讀取wait方法避免本句柄放棄對象鎖多線程避免死鎖,進入期待此對象的等待鎖定池,只有對于此對象發出notify方法(或notifyall)后本線程才開啟對象鎖定池準備拿到對象鎖開啟運行狀況

當兩個線程開啟時,第一個線程必須獲得第二個線程的一個屬性,第二個線程必須獲得第一個線程的一個屬性的之后,互相期待別人線程傳遞此對象時會導致死鎖,造成死鎖的狀況的條件也有要使用synchronized關鍵字調用object.wait()時,線程先應獲取這個對象的對象鎖,當前線程需要在鎖對象維持同步,把當前線程添加至等待隊列中,隨后另一線程可以同步同一個對象鎖來讀取object.notify(),這樣將激活原本期待中的線程,然后釋放該鎖(3)線程2的run()方法中同步代碼塊先獲得lock2的對象鎖,接著獲取lock1的對象鎖,當然此時lock1的對象鎖已經被線程1鎖,線程2肯定是要等待句柄1釋放lock1的對象鎖的

wait是object類的方式,對此對象讀取wait方法避免本句柄放棄對象鎖,進入期待此對象的等待鎖定池,只有對于此對象發出notify方法(或notifyall)后本線程才開啟對象鎖定池準備拿到對象鎖開啟運行狀況里面的舉例比較簡單,就不再介紹了,需要強調的是在使用互斥鎖的過程中最有可能會出現死鎖:兩個線程試圖同時占用兩個資源,并按不同的順序鎖定相應的互斥鎖,例如兩個線程都應該鎖定互斥鎖1跟互斥鎖2,a線程先鎖定互斥鎖1,b線程先鎖定互斥鎖2,這時就發生了死鎖需要切記的是在使用互斥鎖的過程中最有可能會出現死鎖:兩個線程試圖同時占用兩個資源,并按不同的順序鎖定相應的互斥鎖,例如兩個線程都應該鎖定互斥鎖1跟互斥鎖2,a線程先鎖定互斥鎖1多線程避免死鎖,b線程先鎖定互斥鎖2,這時就出現了死鎖

本文來自互聯網,由機器人自動采編,文章內容不代表本站觀點,請讀者自行辨別信息真偽,如有發現不適內容,請及時聯系站長處理。

    相關閱讀
    福彩山东时时彩 北单比分3串1过滤模式 聚乐彩安卓 德州麻将怎么打 哪些公司用免费模式赚钱了 北京快乐8 蛮荒搜神记升级 赚钱 重庆快乐10分 采购人员如何赚钱 安徽快三 哪些观赏鱼可以赚钱 多台手机 注册 赚钱吗 什么香烟最赚钱 网络捕鱼游戏排行 排列3 河南麻将一副多少张牌 营业执照代办赚不赚钱