Linux的strace命令跟蹤線程死鎖

2020-12-17 閒聊代碼

strace命令,是Linux提供的跟蹤系統調用的命令,需要sudo或root權限,可以查看進程(線程)使用的系統調用。

基本用法:sudo strace -p 進程號

如果一個線程遞歸獲取同一個鎖,或者多個線程以不同的順序獲取多個鎖,那麼就會導致至少有一個線程在持有鎖的情況下再次等待在一個鎖上(持有的鎖和等待的鎖可能相同或不同),導致死鎖(deadlock)。

這時,至少有一個線程會等在futex()系統調用上,可以使用strace命令查看具體哪個線程等在哪個鎖上。

看圖中的例子,線程函數thread()連續兩次調用pthread_mutex_lock()加鎖g_mutex,導致遞歸死鎖。

這時它等在futex系統調用上,等待的鎖是g_mutex。

如果main函數裡打開注釋的pthread_join,那麼是等不到子線程返回的。

假設程序的文件名是a.out,在死鎖後:

1,首先使用ps -ef | grep a.out 查看所有的名字叫a.out的進程,如圖。

進程號2992的就是a.out,隨後的2609表示的是父進程,即啟動它的shell進程的pid。

2,使用top -H -p 2992查看該進程下的所有線程,這裡只有2個線程,其中與2992同號的是主線程。

top -H -p 進程號,可以查看所有的線程,其中%CPU顯示該線程的CPU使用率,越活躍的線程這個值越大。

這裡只是為了獲取所有的線程號。

3,然後用sudo strace -p 線程號,去跟蹤它的系統調用。

2992調用了nanosleep ()函數,納秒休眠,與我們在函數裡寫的while (1) sleep(1);代碼相符合。

2993則調用了futex()函數,且等待的鎖的地址是0x557a41002040。

4,這時,可以在鎖的初始化的地方,列印鎖的地址,這裡是main函數的第24行,列印的地址對應的鎖為g_mutex。

然後我們可以查看代碼裡使用了g_mutex加鎖的地方,可以確定是16、17行的兩次加鎖導致的。

這麼幾行代碼,是寫不出這問題的:(

只有代碼複雜起來之後,在一定條件下概率觸發的死鎖,才是實際項目裡的常見情況。

這時,strace命令直接確定死鎖的線程和鎖的地址的作用,才可以發揮出來。

只要在步驟4的調試信息中列印了可能導致死鎖的鎖地址,在問題再次出現時就可以用strace跟蹤到目標鎖的變量,進而查到錯誤代碼的位置。

像上圖那麼一改,是不是BUG就不顯眼了:( 捂臉

main函數第43行的continue會跳過45行的解鎖,導致第40行遞歸死鎖,和thread函數的第19行死鎖。

它是個概率問題,因為100是1000的因子,只有thread線程把g_count++到正好是100的倍數,然後在它下一次++之前main線程獲取了鎖,執行到第42行的if條件,才會出現continue越過45行的解鎖,然後死鎖。

下圖的ctrl+c卡斷的地方,就是出現了死鎖的例子。

PS:如果把第42行的100改成500,降低if成立的概率,那麼死鎖的概率會降低。

如果在thread函數的while循環裡加usleep睡眠,那麼相當於提高了main函數獲得鎖的成功率,死鎖的概率會提高。

這兩個辦法可以在調試時採用。

用戶態程序,其實不怎麼怕死鎖,而是怕該鎖的時候沒鎖,把malloc申請的內存破壞了,導致下一次不知道哪裡free或malloc的時候程序掛了。

這屬於多線程+競爭條件+野指針,C語言裡最無語的BUG之一。

另一個是內核的自旋鎖死鎖,只要鎖住一塊CPU,就會鎖住所有CPU,然後printk()列印不了信息了。

相關焦點

  • Java並發編程:如何防止在線程阻塞與喚醒時死鎖
    Java並發編程:多線程如何實現阻塞與喚醒說到suspend與resume組合有死鎖傾向,一不小心將導致很多問題,甚至導致整個系統崩潰。接著看另外一種解決方案,我們可以使用以對象為目標的阻塞,即利用Object類的wait()和notify()方法實現線程阻塞。
  • 嵌入式Linux啟動時間優化的秘密之一工具鏈/應用程式優化
    應用軟體優化   4.1 測量strace   strace允許跟蹤應用程式及其子級進行的所有系統調用。對於開發非常有用:   了解如何在用戶空間上花費時間   例如,輕鬆查找打開嘗試(open()),文件訪問(read() /write() )和內存分配(mmap2() )。
  • Linux常用命令 - curl
    將輸出保存到文件中若要保存 curl 命令的結果,請使用-o 或-O 選項。如果你嘗試檢索非 www 版本的 google. com,你會注意到,你不但沒有獲得頁面的來源,反而會被重定向到 www 版本:curl baidu.com選項指示 curl 跟蹤任何重定向,直到它到達最終目的地: curl -L baidu.com
  • DB之事務隔離級別、間隙鎖與死鎖
    (3)在這個級別,可能導致大量的超時現象和鎖競爭2 死鎖2.1 什麼是死鎖所謂死鎖,是指多個進程在運行過程中因爭奪資源而造成的一種僵局,當進程處於這種僵持狀態時,若無外力作用,它們都將無法再向前推進。因此我們舉個例子來描述,如果此時有一個線程A,按照先鎖a再獲得鎖b的的順序獲得鎖,而在此同時又有另外一個線程B,按照先鎖b再鎖a的順序獲得鎖。
  • JVM 常用命令行工具
    ,還可以查詢 finalize 執行隊列、Java 堆和方法區的詳細信息,如空間使用率、當前用的是哪種收集器等jmap [option] vmidoption 選項的合法值與具體含義六、虛擬機堆轉儲快照分析工具JDK 提供 jhat(JVM Heap Analysis Tool)命令和 jmap 搭配使用,用來分析 jmap 生成的堆轉儲快照。
  • Linux系統下Java通過shell腳本監控重啟服務
    簡介 最近運維人員提出需求,增加一個運維頁面, 查詢當前的業務進程信息包括:進程名稱、啟動命令、啟動時間、運行時間等,可以通過頁面點擊重啟按鈕,可以重啟後端的一系列系統進程。
  • Java並發編程:多線程如何實現阻塞與喚醒
    線程的阻塞和喚醒在多線程並發過程中是一個關鍵點,當線程數量達到很大的數量級時,並發可能帶來很多隱蔽的問題。如何正確暫停一個線程,暫停後又如何在一個要求的時間點恢復,這些都需要仔細考慮的細節。
  • 幫你精通Linux:簡約卻不簡單的ls命令
    ls 命令即 list directory contents是我們最為熟悉的Linux命令。它就如車載或者手機中的導航地圖,徹底解放了我們的大腦,片刻不能離身。否則我們下樓取個快遞,都得繞18道彎才能勉強找回家。
  • 如何將 Linux 終端中命令的輸出保存到文件中 | Linux 中國
    當然你可以在 Linux 終端中複製和粘貼,但是有更好的方法可以在 Linux 命令行中保存 shell 腳本或命令的輸出,讓我演示給你看。 本文字數:1659,閱讀時長大約:2分鐘 https://linux.cn/article-12920-1.html 作者:Abhishek Prakash 譯者:MjSeven 當你在 Linux 終端中運行命令或腳本時
  • linux常用命令總結
    init 0其他重啟命令 reboot 重啟系統 reboot -h now 立即重啟注意:生產環境中,關機命令和重啟命令謹慎執行。>1幫助命令① man英文:manual 命令路徑:/usr/bin/man 執行權限:所有用戶作用:獲取命令或配置文件的幫助信息語法:man [命令/配置文件]
  • MySQL死鎖分析與解決之路
    來自:貝殼DBA咱們使用 MySQL 大概率上都會遇到死鎖問題,這實在是個令人非常頭痛的問題。本文將會對死鎖進行相應介紹,對常見的死鎖案例進行相關分析與探討,以及如何去儘可能避免死鎖給出一些建議。--什麼是死鎖 --死鎖是並發系統中常見的問題,同樣也會出現在資料庫MySQL的並發讀寫請求場景中。
  • 從串口驅動到Linux驅動模型,想轉Linux的必會!
    在一般的系統當中,都可以在這個目錄下找到linux常用的命令。系統所需要的那些命令位於此目錄。/boot:Linux的內核及引導系統程序所需要的文件目錄,比如 vmlinuz initrd.img 文件都位於這個目錄中。在一般情況下,GRUB或LILO系統引導管理器也位於這個目錄。/cdrom:這個目錄在剛剛安裝系統的時候是空的。可以將光碟機文件系統掛在這個目錄下。
  • 一張圖看懂Linux內核中Percpu變量的實現
    但你知道嗎,不僅是在程式語言中,在linux內核中,也有一個類似的機制,用來實現類似的目的,它叫做percpu變量。percpu變量,顧名思義,就是對於同一個變量,每個cpu都有自己的一份,它可以被用來存放一些cpu獨有的數據,比如cpu的id,cpu上正在運行的線程等等,因該機制可以非常方便的解決一些特定問題,所以在內核編程中被廣泛使用。
  • linux系統中通過dos2unix命令轉換windows系統中編輯的文件
    使用過linux系統的朋友都知道,linux和windows換行符是不同的,Windows格式文件的換行符為\r\n ,而Unix&Linux文件的換行符為\n. dos2unix命令就是將dos文件轉換為unix、linux格式 ,其實就是dos2unix命令將文件中的\
  • 12個有趣的Linux終端命令
    那你一定不知道下面這些有趣的 Linux 命令吧。Linux 終端是用來完成複雜的工作的,我們有很多有用的 linux 命令奇技淫巧來幫助你。但是,你知道你還可以用終端來做很多有趣的事嗎?如果你不知道,沒關係,大多數 Linux 用戶也都只把終端視為一個用來管理系統和開發工作的交互界面。
  • Linux系統監控工具atop
    >clones 表示在監控周期(默認10s)內 clone() 系統調用次數linux 中進程有兩種 sleep 狀態:interruptible sleep: 進程接收系統信號,可以被系統信號中斷uninterruptible sleep
  • Linux shell命令總結大全
    本文轉載自【微信公眾號:java進階架構師,ID:java_jiagoushi】經微信公眾號授權轉載,如需轉載與原文作者聯繫前言Linux shell命令應該算是非常入門的東西,權當給大家做個記錄。但是實際上在使用的時候,會遇到各種各樣的問題,前幾天我在我們的項目上需要做一個功能,根據進程名字殺死這個進程,下面是過程1、我們正常需要的操作是$ps |grep xxx $kill -9 xx2、kill命令是常用的,但是用killall
  • Linux命令之cd詳解,然而CDPATH是什麼鬼,有什麼用?
    cd命令是Linux中最常用的命令之一,它用於切換目錄(最基本的命令行操作之一)。但是大多數用戶都只限於cd的基本用法,其實這工具還提供了許多其他非常有用的小操作。下面就讓我們一起溫故一下這個命令吧。注意,下面提到的所有示例和說明都在Ubuntu 16.04上進行了測試。1. cd 如何切換你的當前目錄?
  • Linux系統的Linux應該怎麼讀?正確讀法在這裡,很多人都讀錯了!
    1、linux發音五花八門版本頗多,見到和聽到的不下10種。根據linux的創始人Linus Torvalds的說法,Linux的發音和「Minix」是押韻的。3、有人綜合網上和linux自己的讀音,概括出幾個自認為最合適也最通用的讀法:/li'n^ks/(「裡那克斯」)或/'li:nэks/(「裡訥克斯」)或/li'nju:ks/(「裡紐克斯」)。4、這幾個應該是誰都聽得懂的。至於哪個比較正宗,當然是linux的原因。但事實上使用linux哪種讀法的人似乎都不在少數。