Linux:線程安全、可重入、死鎖

線程安全及可重入概念

線程安全:多個線程併發同一段代碼時,不會出現不同的結果,常見於對全局變量和靜態變量進行操作,並且沒有被鎖保護的情況下,會出現線程不安全的問題。
可重入:同一個函數被不同的執行流調用,當前一個流程沒有被執行完,就有其他的執行流再次進入稱爲重入,一個函數在重入的情況下,運行結果不會出現任何不同或者任何問題,則該函數稱爲可重入函數,(因此可以看出,一個函數可重入,一定是線程安全的),否則稱爲不可重入函數。

  • 常見線程不安全的的情況
    (1)不保護共享變量的函數
    (2)函數狀態鎖着被調用,狀態發生變化的函數
    (3)返回指向靜態變量指針的函數
    (4)調用線程不安全函數的函數
  • 常見線程安全的情況
    (1)每個線程對全局變量或者靜態變量只有讀取的權限,沒有寫入的權限,這些線程一般是安全的
    (2)類或者接口對於線程來說都是原子操作
    (3)多個線程之間的切換不會導致該接口的指向結果存在二義性
  • 常見不可重入的情況
    (1)調用了malloc/free函數,因爲malloc函數是用全局鏈表來管理堆的
    (2)調用了標準I/O庫函數,因爲標準I/O庫很多實現是以不可重入的方式是用全局數據結構
    (3)可重入函數體內使用了靜態的數據結構
  • 常見可重入情況
    (1)不使用全局變量或者靜態變量
    (2)不使用用malloc或者new開闢的空間
    (3)不調用不可重入函數
    (4)不返回靜態或全局數據,所有數據都由函數的調用者提供
    (5)是用本地數據,或者通過製作全局數據的本地拷貝來保護全局數據
  • 可重入與線程安全的聯繫
    函數可重入,就是線程安全的;函數不可重入,就是不能被多個線程使用,可能引發線程安全問題;若一個函數中有全局變量,那麼這個函數既不是線程安全也不是可重入的
  • 可重入與線程安全區別
    可重入函數是線程安全的一種,線程安全不一定是可重入的,而可重入函數一定是線程安全的;若對臨界資源的訪問加上鎖,則這個函數是線程安全的,但是如果這個重入函數若鎖還未被釋放則會產生死鎖,因此是不可重入的
死鎖
  • 死鎖概念
    多個執行流對鎖資源進行爭搶訪問,因爲推進順序不當,而導致互相等待,最終造成程序流程無法繼續的情況。例如A申請B中不會釋放的資源,B申請C中不會釋放的資源,C申請A中不會釋放的資源,這樣就會處於永久等待狀態。
  • 死鎖四個必要條件(重要,必須滿足)
    (1)互斥條件:一個資源每次只能被一個執行流使用
    (2)請求和保持條件:一個執行流因請求資源而阻塞時,對已獲得的資源保持不放
    (3)不剝奪條件:一個執行流已獲得的資源,在未使用完之前,不能強行剝奪
    (4)循環等待條件:若干執行流之間形成一種頭尾相接的循環等待資源的關係
    例如線程1申請A鎖,申請完申請B鎖,線程2申請B鎖,申請完申請A鎖,因此線程1申請完A鎖想要申請B鎖,申請不到,線程1掛起,自己申請的鎖保持不放,沒有釋放A鎖,因此線程2想要申請A鎖申請不到,線程2掛起,自己申請的鎖保持不放,沒有釋放B鎖,意味着線程1 2永遠不會被喚醒,產生死鎖
    只有一把鎖,一個線程也可能產生死鎖,例如線程申請了鎖,然後又申請了一次,沒有申請成功,掛起,想要喚醒就要釋放這個鎖,但是此時線程掛起,這個鎖被這個線程拿着,沒有釋放這個鎖,因此就產生了死鎖。
  • 避免死鎖
    (1)破壞死鎖的四個必要條件(互斥條件不能破壞)
    (2)加鎖順序一致
    (3)避免鎖未被釋放的場景
    (4)資源一次性分配
  • 避免死鎖算法
    (1)死鎖檢測算法
    (2)銀行家算法
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章