【轉】一個 Linux 上分析死鎖的簡單方法


簡介

死鎖 (deallocks): 是指兩個或兩個以上的進程(線程)在執行過程中,因爭奪資源而造成的一種互相等待的現象,若無外力作用,它們都將無法推進下去。此時稱系統處於死鎖狀態或系統產生了死鎖,這些永遠在互相等待的進程(線程)稱為死鎖進程(線程)。 由於資源占用是互斥的,當某個進程提出申請資源后,使得有關進程(線程)在無外力協助下,永遠分配不到必需的資源而無法繼續運行,這就產生了一種特殊現象死鎖。

一種交叉持鎖死鎖的情形,此時執行程序中兩個或多個線程發生永久堵塞(等待),每個線程都在等待被其它線程占用並堵塞了的資源。例如,如果線程 1 鎖住了記錄 A 並等待記錄 B,而線程 2 鎖住了記錄 B 並等待記錄 A,這樣兩個線程就發生了死鎖現象。在計算機系統中 , 如果系統的資源分配策略不當,更常見的可能是程序員寫的程序有錯誤等,則會導致進程因競爭資源不當而產生死鎖的現象。

產生死鎖的四個必要條件

(1) 互斥條件:一個資源每次只能被一個進程(線程)使用。
(2) 請求與保持條件:一個進程(線程)因請求資源而阻塞時,對已獲得的資源保持不放。
(3) 不剝奪條件 : 此進程(線程)已獲得的資源,在末使用完之前,不能強行剝奪。
(4) 循環等待條件 : 多個進程(線程)之間形成一種頭尾相接的循環等待資源關系。

圖 1. 交叉持鎖的死鎖示意圖:

注釋:在執行 func2 和 func4 之后,子線程 1 獲得了鎖 A,正試圖獲得鎖 B,但是子線程 2 此時獲得了鎖 B,正試圖獲得鎖 A,所以子線程 1 和子線程 2 將沒有辦法得到鎖 A 和鎖 B,因為它們各自被對方占有,永遠不會釋放,所以發生了死鎖的現象。

使用 pstack 和 gdb 工具對死鎖程序進行分析

pstack 在 Linux 平台上的簡單介紹

pstack 是 Linux(比如 Red Hat Linux 系統、Ubuntu Linux 系統等)下一個很有用的工具,它的功能是打印輸出此進程的堆棧信息。可以輸出所有線程的調用關系棧。

gdb 在 Linux 平台上的簡單介紹

GDB 是 GNU 開源組織發布的一個強大的 UNIX 下的程序調試工具。Linux 系統中包含了 GNU 調試程序 gdb,它是一個用來調試 C 和 C++ 程序的調試器。可以使程序開發者在程序運行時觀察程序的內部結構和內存的使用情況 .

gdb 所提供的一些主要功能如下所示:

1 運行程序,設置能影響程序運行的參數和環境 ;

2 控制程序在指定的條件下停止運行;

3 當程序停止時,可以檢查程序的狀態;

4 當程序 crash 時,可以檢查 core 文件;

5 可以修改程序的錯誤,並重新運行程序;

6 可以動態監視程序中變量的值;

7 可以單步執行代碼,觀察程序的運行狀態。

gdb 程序調試的對象是可執行文件或者進程,而不是程序的源代碼文件。然而,並不是所有的可執行文件都可以用 gdb 調試。如果要讓產生的可執行文件可以用來調試,需在執行 g++(gcc)指令編譯程序時,加上 -g 參數,指定程序在編譯時包含調試信息。調試信息包含程序里的每個變量的類型和在可執行文件里的地址映射以及源代碼的行號。gdb 利用這些信息使源代碼和機器碼相關聯。gdb 的基本命令較多,不做詳細介紹,大家如果需要進一步了解,請參見 gdb 手冊。

清單 1. 測試程序
清單 2. 編譯測試程序
清單 3. 查找測試程序的進程號
清單 4. 對死鎖進程第一次執行 pstack(pstack –進程號)的輸出結果
清單 5. 對死鎖進程第二次執行 pstack(pstack –進程號)的輸出結果

連續多次查看這個進程的函數調用關系堆棧進行分析:當進程吊死時,多次使用 pstack 查看進程的函數調用堆棧,死鎖線程將一直處於等鎖的狀態,對比多次的函數調用堆棧輸出結果,確定哪兩個線程(或者幾個線程)一直沒有變化且一直處於等鎖的狀態(可能存在兩個線程 一直沒有變化)。

輸出分析:

根據上面的輸出對比可以發現,線程 1 和線程 2 由第一次 pstack 輸出的處在 sleep 函數變化為第二次 pstack 輸出的處在 memset 函數。但是線程 4 和線程 5 一直處在等鎖狀態(pthread_mutex_lock),在連續兩次的 pstack 信息輸出中沒有變化,所以我們可以推測線程 4 和線程 5 發生了死鎖。

Gdb into thread輸出:

清單 6. 然后通過 gdb attach 到死鎖進程
清單 7. 切換到線程 5 的輸出
清單 8. 線程 4 和線程 5 的輸出

從上面可以發現,線程 4 正試圖獲得鎖 mutex1,但是鎖 mutex1 已經被 LWP 為 6722 的線程得到(__owner = 6722),線程 5 正試圖獲得鎖 mutex2,但是鎖 mutex2 已經被 LWP 為 6723 的 得到(__owner = 6723),從 pstack 的輸出可以發現,LWP 6722 與線程 5 是對應的,LWP 6723 與線程 4 是對應的。所以我們可以得出, 線程 4 和線程 5 發生了交叉持鎖的死鎖現象。查看線程的源代碼發現,線程 4 和線程 5 同時使用 mutex1 和 mutex2,且申請順序不合理。

總結

本文簡單介紹了一種在 Linux 平台下分析死鎖問題的方法,對一些死鎖問題的分析有一定作用。希望對大家有幫助。理解了死鎖的原因,尤其是產生死鎖的四個必要條件,就可以最大可能地避免、預防和解除死鎖。所以,在系統設計、進程調度等方面注意如何不讓這四個必要條件成立,如何確定資源的合理分配算法,避免進程永久占據系統資源。此外,也要防止進程在處於等待狀態的情況下占用資源 , 在系統運行過程中,對進程發出的每一個系統能夠滿足的資源申請進行動態檢查,並根據檢查結果決定是否分配資源,若分配后系統可能發生死鎖,則不予分配,否則予以分配。因此,對資源的分配要給予合理的規划,使用有序資源分配法和銀行家算法等是避免死鎖的有效方法。

 

轉自:http://www.ibm.com/developerworks/cn/linux/l-cn-deadlock/


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM