gdb 中step、next與finish的區別
step 就是單步執行,遇到子函數就進入並且繼續單步執行;在其他調試其中相當於step-into命令,作用是移動到下一個可執行的代碼行。如果當前行是一個函數調用,則調試器進入函數並停止在函數體的第一行。step可以幫助初步揭開代碼位置的謎團,例如:函數調用和函數本身可能在不同的文件中。
next 是在單步執行時,在函數內遇到子函數時不會進入子函數內單步執行,而是將子函數整個執行完再停止,也就是把子函數整個作為一步。在其他調試器中相當於step-over,作用是在同一個調用棧層中移動到下一個可執行的代碼行。調試器不會進入函數體。如果當前行是函數的最后一行,則,next將進入下一個棧層,並在調用函數的下一行停止。
finish 就是但單步執行到子函數內時,用step out就可以執行完子函數余下部分,並返回到上一層函數。在其他調試器中相當於step-out,作用是在棧中前進到到下一層,並在調用函數的下一行停止。
多線程的gdb調試
假設現在有一個主線程創建了一個子線程。
gdb調試時,設置斷點,單步調試到pthread_create處的時候,這時候會創建子線程,會出現如下信息
[New Thread 0x7ffff6fd1700 (LWP 6376)]
默認情況下,gdb只跟蹤主線程,新創建的線程都被阻塞在pthread_create函數處。
info threads
可以調試的所有線程,gdb會為每個線程分配一個ID,這個ID和線程ID不同,ID號一般從1開始。
如下,表示當前有兩個線程1和2,*表示跟蹤主線程1
(gdb) info threads
Id Target Id Frame
2 Thread 0x7ffff6fd1700 (LWP 6376) "test" 0x00007ffff70d0851 in clone ()
from /lib64/libc.so.6
* 1 Thread 0x7ffff7fee740 (LWP 6375) "test" main (argc=1, argv=0x7fffffffe2d8) at test.cpp:31
thread ID
切換當前調試的線程為指定ID號,ID是gdb分配的序號,不是線程TID。
set scheduler-locking off|on
on鎖定其他線程,只有當前選擇調試的線程執行,off表示不鎖定任何線程,當運行到斷點處,將所有的線程都暫停下來,直到指定某個線程繼續執行,如果在當前線程下使用continue的話會啟動所有線程(GDB默認)。
多線程調試控制指令
thread apply ID1 ID2 ...IDn gdb_command
指定多個線程執行gdb中的command指令
thread apply all command
指定所有線程執行gdb中的command指令
non-stop模式
上面說過一個線程中斷在一個斷點上,其他所有的線程都會被freeze。新版本的GDB中,引入了non-stop模式,在這個模式下:
-
當某個或多個線程在一個斷點上,其他線程仍會並行運行
-
你可以選擇某個被中斷的線程,只讓他運行。
-
non-stop模式表示不停止模式,除了斷點有關的進程會被停下來,其他線程會繼續執行。
設置non-stop模式,打開gdb后,在開始r之前,首先連續輸入下面的指令
set target-async 1
set pagination off
set non-stop on
總結調試多線程的命令
info threads
顯示當前可調試的所有線程,每個線程會有一個GDB為其分配的ID,后面操作線程的時候會用到這個ID。 前面有*的是當前調試的線程
thread ID(1,2,3…)
切換當前調試的線程為指定ID的線程
break thread_test.c:123 thread all
(例:在相應函數的位置設置斷點break pthread_run1) 在所有線程中相應的行上設置斷點
thread apply ID1 ID2 command
讓一個或者多個線程執行GDB命令command
thread apply all command
讓所有被調試線程執行GDB命令command
set scheduler-locking
選項 command 設置線程是以什么方式來執行命令
set scheduler-locking off
不鎖定任何線程,也就是所有線程都執行,這是默認值
set scheduler-locking on
只有當前被調試程序會執行
set scheduler-locking on step
在單步的時候,除了next過一個函數的情況(熟悉情況的人可能知道,這其實是一個設置斷點然后continue的行為)以外,只有當前線程會執行
線程池調試技巧
調試進程池和線程池中的程序一個不錯的方法,是將池中的個數減少至1,觀察是否正確,然后逐步增加線程數量,調試線程的同步是否正確