inux下,多線程程序死循環問題調試
分類: 網絡通訊 2011-12-02 15:27 161人閱讀 評論(0) 收藏 舉報
當你的軟件在某個時刻停止服務,CPU佔用達到100%+,這種問題一個可能的原因是產生了死循環,
假設程序某處存在潛在的死循環,並在某種條件下會引發,本文以一個示例來定位出現死循環的位置。
當程序某處存在死循環,通常定位問題及縮小範圍的方法是,在可疑的代碼處加log,或者註釋掉可疑代碼,
這對於容易重現問題的程序來說還好,但對於“偶爾”纔會產生問題程序卻很難調試,因爲我們很難重現程序故障。
本文所述的調試過程正是在這種情況下,假設問題已經出現,我們要求環境保護現場,即出問題的程序還在運行中。
1.我們首先要知道是哪個線程出了問題:
首先查一下出問題進程的pid,例如
ovtsvn@ovtsvn:~/MASS4/src/icdn/src$ ps -ef | grep icdn
ovtsvn 11065 1 50 11:57 ? 00:00:07 ./icdn
ovtsvn 11076 10971 0 11:57 pts/2 00:00:00 grep icdn
ovtsvn@ovtsvn:~/MASS4/src/icdn/src$
然後top命令查看線程信息:
top -H -p 11065
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
11073 ovtsvn 25 0 325m 3980 2236 R 100 0.4 1:40.84 icdn
11065 ovtsvn 18 0 325m 3980 2236 S 0 0.4 0:00.01 icdn
11066 ovtsvn 18 0 325m 3980 2236 S 0 0.4 0:00.00 icdn
11067 ovtsvn 15 0 325m 3980 2236 S 0 0.4 0:00.00 icdn
11068 ovtsvn 15 0 325m 3980 2236 S 0 0.4 0:00.00 icdn
11069 ovtsvn 18 0 325m 3980 2236 S 0 0.4 0:00.00 icdn
11070 ovtsvn 18 0 325m 3980 2236 S 0 0.4 0:00.00 icdn
11071 ovtsvn 22 0 325m 3980 2236 S 0 0.4 0:00.00 icdn
11072 ovtsvn 15 0 325m 3980 2236 R 0 0.4 0:00.00 icdn
從上面可以看出,出問題線程PID爲11073
2.接下來,我們用gdb來attach目標進程
執行: gdb icdn 11065
在gdb中,列出線程狀態:
(gdb) info threads
9 Thread 47056948181264 (LWP 11066) 0x00002acc4a3dec91 in nanosleep () from /lib/libc.so.6
8 Thread 47056956573968 (LWP 11067) 0x00002acc4a406fc2 in select () from /lib/libc.so.6
7 Thread 47056964966672 (LWP 11068) 0x00002acc4a3dec91 in nanosleep () from /lib/libc.so.6
6 Thread 47056973359376 (LWP 11069) 0x00002acc4a3dec91 in nanosleep () from /lib/libc.so.6
5 Thread 47056981752080 (LWP 11070) 0x00002acc4a3dec91 in nanosleep () from /lib/libc.so.6
4 Thread 47056990144784 (LWP 11071) 0x00002acc4a40e63c in recvfrom () from /lib/libc.so.6
3 Thread 47057194060048 (LWP 11072) 0x00002acc4a406fc2 in select () from /lib/libc.so.6
2 Thread 47057226893584 (LWP 11073) CSendFile::SendFile (this=0x2acc5d4aff40, pathname=@0x2acc5d4afee0)
at ../src/csendfile.cpp:101
1 Thread 47056939784832 (LWP 11065) 0x00002acc4a3dec91 in nanosleep () from /lib/libc.so.6
(gdb)
gdb已經列出了各線程正在執行的函數,我們需要更多信息,記住11073對應的行首標號,這是gdb爲線程分配的id,這裏爲2,然後執行切換:
(gdb) thread 2
[Switching to thread 2 (Thread 47057226893584 (LWP 11073))]#0 CSendFile::SendFile (this=0x2acc5d4aff40, pathname=@0x2acc5d4afee0)
at ../src/csendfile.cpp:101
101 while(1)
(gdb)
bt一下:
(gdb) bt
#0 CSendFile::SendFile (this=0x2acc5d4aff40, pathname=@0x2acc5d4afee0) at ../src/csendfile.cpp:101
#1 0x000000000040592e in CIcdn::TaskThread (pParam=0x7fff617eafe0) at ../src/cicdn.cpp:128
#2 0x00002acc4a90b73a in start_thread () from /lib/libpthread.so.0
#3 0x00002acc4a40d6dd in clone () from /lib/libc.so.6
#4 0x0000000000000000 in ?? ()
來看一下101行的代碼:
(gdb) l
96 }
97
98 int CSendFile::SendFile(const string& pathname)
99 {
100 int n;
101 while(1)
102 {
103 n++;
104 }
105 //read file and send
現在我們定位到了出問題的代碼位置,這裏的循環只用來演示的。
最後別忘了detach
gdb 多線程調試
http://hi.baidu.com/hcq11/blog/item/9f5bfc6e696209d680cb4a25.html
http://hi.baidu.com/litto/blog/item/759389dd198111375882dd1e.html
http://blogold.chinaunix.net/u3/94700/showart_2389432.html <推薦閱讀>
先介紹一下GDB多線程調試的基本命令。
info threads 顯示當前可調試的所有線程,每個線程會有一個GDB爲其分配的ID,後面操作線程的時候會用到這個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
這樣的話,只調試當前線程
13553575292 w
Linxu 進程死循環問題調試
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章
CentOS SVN服務器搭建
CentOS SVN 操作系統:CentOS5.6 X86_64 subversion: subversion-1.6.11-10.el5_8 mo
liyw-9192
2020-07-05 15:36:32
u-boot-1.1.6編譯過程中出現cannot find -lc
伍德禅师
2020-07-04 13:36:39
ubuntu-10.04下 聯想 卲陽E46L以太 網驅動程序安 裝
伍德禅师
2020-07-04 13:36:39
Gnome2.x快捷鍵
fishOnFly
2020-06-25 20:05:13
Linux下hosts,host.conf,resolv.conf的區別
數據通信
2020-05-31 12:39:44
kubernetes 二進制安裝 遇到 etcd 不能啓動報錯 處理
安享落幕
2020-05-13 16:14:27
Kubadm方式安裝K8s----flannel 網絡插件
安享落幕
2020-03-18 15:20:03
Linux 文本處理利器--Awk常用命令
低調的男孩
2020-03-02 13:52:19
linux如何進入單用戶模式
angle0615303
2020-02-24 11:13:42
centos 6 嚐鮮紀實 - PH67A/P67A 主板安裝
suvi
2020-02-22 10:53:23
How To Reset Root User Password In CentOS/RHEL8
SoloLinux
2020-02-22 06:37:32
CentOS 8 系統圖形化安裝教程(超詳細)
低調的男孩
2020-02-20 13:47:55
Webmin:是目前功能最強大的基於Web的Unix系統管理工具
安享落幕
2019-11-12 14:45:14