GDB 調試多線程

原文地址:

http://blog.csdn.net/coolyinger/article/details/8114069


一.理論片


GDB多線程調試的基本命令。


info threads 顯示當前可調試的所有線程,每個線程會有一個GDB爲其分配的ID,後面操作線程的時候會用到這個。 前面有*的是當前調試的線程。
thread ID 切換當前調試的線程爲指定ID的線程。
break thread_test.c:123 thread all
在所有線程中相應的行上設置斷點
thread apply ID1 ID2 command 讓一個或者多個線程執行GDB命令command。
thread apply all command 
讓所有被調試線程執行GDB命令command。
set scheduler-locking off|on|step 估計是實際使用過多線程調試的人都可以發現,在使用step或者continue命令調試當前被調試線程的時候,其他線程也是同時執行的,怎麼只讓被調試程序執行呢?通過這個命令就可以實現這個需求。off 不鎖定任何線程,也就是所有線程都執行,這是默認值。 on 只有當前被調試程序會執行。 step 在單步的時候,除了next過一個函數的情況(熟悉情況的人可能知道,這其實是一個設置斷點然後continue的行爲)以外,只有當前線程會執行。

 

gdb對於多線程程序的調試有如下的支持:

  • 線程產生通知:在產生新的線程時, gdb會給出提示信息

(gdb) r
Starting program: /root/thread 
[New Thread 1073951360 (LWP 12900)] 
[New Thread 1082342592 (LWP 12907)]---以下三個爲新產生的線程
[New Thread 1090731072 (LWP 12908)]
[New Thread 1099119552 (LWP 12909)]

  • 查看線程:使用info threads可以查看運行的線程。

(gdb) info threads
  4 Thread 1099119552 (LWP 12940)   0xffffe002 in ?? ()
  3 Thread 1090731072 (LWP 12939)   0xffffe002 in ?? ()
  2 Thread 1082342592 (LWP 12938)   0xffffe002 in ?? ()
* 1 Thread 1073951360 (LWP 12931)   main (argc=1, argv=0xbfffda04) at thread.c:21
(gdb)

注意,行首的數字爲gdb分配的線程號,對線程進行切換時,使用該該號碼。

另外,行首的星號標識了當前活動的線程

  • 切換線程:使用 thread THREADNUMBER 進行切換,THREADNUMBER 爲上文提到的線程號。下例顯示將活動線程從 1 切換至 4。

(gdb) info threads
   4 Thread 1099119552 (LWP 12940)   0xffffe002 in ?? ()
   3 Thread 1090731072 (LWP 12939)   0xffffe002 in ?? ()
   2 Thread 1082342592 (LWP 12938)   0xffffe002 in ?? ()
* 1 Thread 1073951360 (LWP 12931)   main (argc=1, argv=0xbfffda04) at thread.c:21
(gdb) thread 4
[Switching to thread 4 (Thread 1099119552 (LWP 12940))]#0   0xffffe002 in ?? ()
(gdb) info threads
* 4 Thread 1099119552 (LWP 12940)   0xffffe002 in ?? ()
   3 Thread 1090731072 (LWP 12939)   0xffffe002 in ?? ()
   2 Thread 1082342592 (LWP 12938)   0xffffe002 in ?? ()
   1 Thread 1073951360 (LWP 12931)   main (argc=1, argv=0xbfffda04) at thread.c:21
(gdb)

後面就是直接在你的線程函數裏面設置斷點,然後continue到那個斷點,一般情況下多線程的時候,由於是同時運行的,最好設置 set scheduler-locking on

這樣的話,只調試當前線程 

 --------------------------------------------------------------------------------------------------------------

二.實戰片


調試程序:

  1. #include<stdio.h>  
  2. #include <stdlib.h>  
  3. #include <pthread.h>  
  4. #include <unistd.h>  
  5.   
  6. void * fun1 (void *arg1)  
  7. {  
  8.     printf ("[pthread1]  -- start\n");  
  9.     sleep (2);  
  10.     printf ("[pthread1]  -- end\n");  
  11.     pthread_exit ((void *) NULL);  
  12. }  
  13.   
  14. void * fun2 (void *arg1)  
  15. {  
  16.     printf ("[pthread2]  -- start\n");  
  17.     sleep (2);  
  18.     printf ("[pthread2]  -- end\n");  
  19.     pthread_exit ((void *) NULL);  
  20. }  
  21.   
  22. int main(void)  
  23. {  
  24.   
  25.     pthread_t pid1, pid2;  
  26.     void *tmp;  
  27.   
  28.     printf ("[main] -- start\n");  
  29.   
  30.     if (pthread_create (&pid1, NULL, fun1, NULL)) {  
  31.         perror ("create pthread1 error\n");  
  32.         exit (1);  
  33.     }  
  34.     if (pthread_create (&pid2, NULL, fun2, NULL)) {  
  35.         perror ("create pthread2 error\n");  
  36.         exit (1);  
  37.     }  
  38.   
  39.     if (pthread_join (pid1, &tmp)) {  
  40.         perror ("join pthread1 error\n");  
  41.         exit (1);  
  42.     }  
  43.   
  44.     if (pthread_join (pid2, &tmp)) {  
  45.         perror ("join pthread2 error\n");  
  46.         exit (1);  
  47.     }  
  48.   
  49.     sleep (2);  
  50.     printf ("[main] -- end\n");  
  51.     return 0;  
  52. }  

本程序有3個線程, main 線程先執行,然後創建2個子線程。創建後main 線程等子線程結束,最後再退出。

多線程程序的順序是未知的,但我們用gdb 調試,可以指定每個線程的前後順序。以這個例子爲例: main 線程創建完 pthread2 和 pthread3 後,不知道

 pthread2 先執行,還是 pthread3 先執行,也不知道是pthread2 先結束還是pthread3 先結束。  但我們這次調試,等main 線程創建完pthread2 後,先指定

pthread2 先執行,先調試它,等pthread2結束了,再調試pthread3,最後返回調試main線程


[plain] view plaincopy
  1. (gdb) b 28                     # 先在main 線程設置斷點,設置到創建 pthread2 線程處  
  2. Breakpoint 1 at 0x4007dc: file d.c, line 28.  
  3.   
  4. 30        if (pthread_create (&pid1, NULL, fun1, NULL)) {  

[plain] view plaincopy
  1. (gdb) set scheduler-locking on     # 在創建pthread2 後,線程的執行順序就不定了,所以我們先設置 scheduler ,指定<單一線程調試>模式  



[plain] view plaincopy
  1. (gdb) n                         # 在這步,pthread2線程已經創建,main線程停在創建pthread3線程處。由於我們是單線程調試,所以pthread2雖然創建了,但沒執行  
  2. [New Thread 0x7ffff7fe5700 (LWP 25412)]  
  3. 34        if (pthread_create (&pid2, NULL, fun2, NULL)) {  



[plain] view plaincopy
  1. (gdb) info thread                 # 察看線程信息,  現在main 創建了pthread2 線程,所以有兩個線程, 我們目前在調試1線程(就是main線程, 星號代表當前線程)  
  2.   Id   Target Id         Frame  
  3.   2    Thread 0x7ffff7fe5700 (LWP 25412) "a.out" 0x0000003bd880dd9c in __lll_lock_wait_private () from /lib64/libpthread.so.0  
  4. * 1    Thread 0x7ffff7fe6740 (LWP 25409) "a.out" main () at d.c:34  


[plain] view plaincopy
  1. (gdb) thread 2                    #  現在我們讓main線程就停在這,去調試 pthread2線程  
  2. [Switching to thread 2 (Thread 0x7ffff7fe5700 (LWP 25412))]  



[plain] view plaincopy
  1. (gdb) b 8                       # pthread2 線程是執行一個函數,所以在函數處加入斷點  
  2. Breakpoint 2 at 0x400778: file d.c, line 8.  



[plain] view plaincopy
  1. (gdb) c                     # pthread2 調試到我們的斷點處  
  2.   
  3. Continuing.  



一直n ,把pthread2 調試完畢


[plain] view plaincopy
  1. (gdb) n           <span style="color:#3333FF;"><strong> </strong></span># pthread2 執行完畢  
  2. 0x0000003bd8807cd7 in start_thread () from /lib64/libpthread.so.0  
  3. Missing separate debuginfos, use: debuginfo-install libgcc-4.7.0-4.fc17.x86_6  


[plain] view plaincopy
  1. (gdb) thread 1         #這時我們跳回 main 線程,去創建 pthread3  
  2. [Switching to thread 1 (Thread 0x7ffff7fe6740 (LWP 25409))]  


[plain] view plaincopy
  1. (gdb) n  
  2. [New Thread 0x7ffff77e4700 (LWP 25424)]  
  3. 39        if (pthread_join (pid1, &tmp)) {  
  4. (gdb) thread 3  
  5. [Switching to thread 3 (Thread 0x7ffff77e4700 (LWP 25424))]  


同上,把pthraed3調試完畢,再跳回 main 線程


[plain] view plaincopy
  1. (gdb) thread 1  
  2. [Switching to thread 1 (Thread 0x7ffff7fe6740 (LWP 25409))]  
  3. #0  main () at d.c:39  
  4. 39        if (pthread_join (pid1, &tmp)) {  


這時main線程停止在 pthread_join 處,如果繼續調試,main線程會阻塞(不確定爲什麼),這時我們設置  set scheduler-locking off 關閉單線程調試,然後繼續調試

main 線程就不會阻塞。






發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章