Linux下的多執行緒除錯

2021-07-09 16:19:29 字數 2226 閱讀 9553

1.取樣輸出

2.gdb除錯(attach, sleep等)

3.利用訊號處理函式

4.strace跟蹤系統呼叫和收到的訊號

5.core檔案

6.log檔案

原處:多執行緒程式可能存在很多潛在的bug,如data race,dead lock,訊號bug等,而這些bug一向很難除錯,現在有很多**都是基於多執行緒程式的除錯技術的,比如model check,死鎖檢測,replay技術等,也有很多對應的工具,如intel的pinplay,微軟的zing等。關於這些技術和工具,如果感興趣可以 google相應的**進一步了解。這裡我主要講述的是我在對二進位制翻譯下多執行緒程式除錯中經常使用的一些方法以及一些除錯經驗,雖然我的除錯的是二進位制翻譯器,但是這些方法也同樣適用於大多數多執行緒程式。

1、最直接的方法就是在源程式插入printf語句來列印出一些有用的變數。這種方法的優點是不用借助其他工具就可以對程式的執行進行觀察,缺點是插入語句的位置、粒度等都需要除錯者自己去權衡,如果插入過多的列印語句,則頻繁的io操作會使程式執行變慢,執行緒行為改變,有些bug甚至不會再出現。至於需要在什麼地方插入語句,首先,只列印有必要的變數,乙個語句可以列印多個變數;其次,在迴圈中,我們可以通過設定一些條件來降低列印的粒度。

假設我們對pc的取值很感興趣,需要列印出所有pc取到過的值,但是大多數情況下,getpc()的返回值都同上一次的返回值相同,這樣我們printf出來的就會有很多重複值。這種情況下我們可以用下面這種插樁方式來去處重複值。通過乙個簡單的判斷就可以省掉很多沒有必要的輸出。很多別的情形,比如我們只關心某一變數等於特定值(比如0)時其他變數的狀態,我們就沒有必要把改變量不等於0時的狀態列印出來。總之,能省則省,只列印我們需要的。

gdb    attach  

這種方法的好處是能夠使gdb對程式執行的影響最小,而且可以只接管程式中某一條我們所關心的執行緒,而其他執行緒不受影響。

這時有人會問,如果執行緒執行過快,我們還沒來得及attach執行緒就已經執行完或者dump掉了,這種情況該怎麼辦?解決方法很簡單,既然執行緒執行過快,我們就讓它等一等,可以在源**中讓我們關心這個執行緒sleep()一小會兒,這樣我們就有足夠的時間來attach它,並且attach的位置我們也可以進行控制,想在**attach,就在**sleep。

3、第三種方法是利用訊號處理函式來獲取一些資訊。在多執行緒程式的壓力測試中,很多錯誤要每隔幾百幾千次執行才能出現一次,而這種錯誤的replay是很困難的,因此捕捉到這種錯誤的現場很重要。這裡我習慣利用訊號處理程式來儲存這樣的現場,這樣你可以晚上寫個指令碼讓程式無限跑,早上起來你會發現程式停在出錯的地方,這是很愜意的事情。

多數多執行緒程式出錯,都是訪問非法記憶體,也就是我們常說的「段錯誤」(segmentation fault),程式發生非法記憶體的訪問,系統會發給執行緒乙個sigsegv訊號,這個訊號預設處理為core掉該執行緒。我們可以對這個訊號進行利用,為其註冊乙個訊號處理函式:

函式引數中,puc是乙個體繫結構相關的指標,不同的體系結構,指標指向的結構不一樣,裡面存放了發生訊號時執行緒的暫存器的值,程式位址等資訊,函式內第一句話的目的就是把void型別轉換成ucontext結構型別,這樣在gdb中可以直接print出該結構的成員。

函式中sleep的作用是讓程式停在訊號處理程式中,以給我們足夠的時間進行attach。如果想讓程式繼續執行下去,手動把loopflag修改為1即可。用while迴圈的目的是我們可以在執行時手動控制sleep的時間。

這種方法同樣適用於其他訊號帶來的bug,比如sigbus等。在二進位制翻譯下,還可以使用這種方法對二進位制翻譯器訊號處理進行跟蹤和除錯,具體使用讀者可以自己去發掘。

4、利用strace得到我們關心的資訊。大多數情況下我們用strace的目的是跟蹤系統呼叫,但其實strace對多執行緒程式的除錯有很大的幫助,使用strace列印多執行緒程式資訊的命令如下:

strace    -f   ./test

如果我們對某些系統呼叫,如gettimeofday,ioctl不感興趣,可以遮蔽掉

strace-f

-etrace=\!gettimeofday,ioctl ./

test

通過strace列印出的資訊,我們可以對什麼時候產生了乙個子執行緒,那個執行緒在等待,哪個執行緒被喚醒,哪個執行緒收到訊號,哪個執行緒core掉有乙個綜合的了解,這些資訊對多執行緒除錯會起到很大的作用。

還有很多方法比如利用core檔案等,很多地方可以查到,我不做累贅的介紹。總之技術是死的,但是方法是靈活的,當傳統方法解決不了乙個問題的時候,可以放開思路嘗試其他的方法。

Linux下GDB除錯多執行緒

1 gdb會每個執行緒分配乙個id,前面有 的表示當前正在除錯的執行緒。gdb info threads id target id frame 2 thread 0x7ffff77ff700 lwp 2481 thread thread func args 0x0 at thread.c 11 1 ...

Linux下多執行緒程式除錯方法

1 最直接的方法就是在源程式插入printf語句來列印出一些有用的變數。這種方法的優點是不用借助其他工具就可以對程式的執行進行觀察,缺點是插入語句的位置 粒度等都需要除錯者自己去權衡,如果插入過多的列印語句,則頻繁的io操作會使程式執行變慢,執行緒行為改變,有些bug甚至不會再出現。至於需要在什麼地...

Linux下多程序多執行緒的除錯

1.linux下gdb除錯常用命令 在除錯前明確 在生成源 的時候加上 g 選項,開始使用 gdb binfile,退出 ctrl d 或 quit。下面是除錯的常用命令。list l 行號 顯示binfile源 接著上次的位置往下列,每次列10行。list l 函式名 列出某個函式的源 r或run...