對(duì)于c++程序來(lái)說(shuō),以segment fault為代表的程序異常行為千奇百怪,沒(méi)有一套比較豐富的工具集去對(duì)付他們,在處理實(shí)際問(wèn)題時(shí)就會(huì)顯得捉襟見(jiàn)肘。本文列舉幾種程序異常的定位方法。
子線程創(chuàng)建不出來(lái)
猜測(cè):go的程序都能創(chuàng)建出子線程,但是c++的創(chuàng)建不出來(lái),但是在 x86 可以,是不是什么 linux 系統(tǒng)限制?
解決方法:加錯(cuò)誤日志進(jìn)行調(diào)試(最 lower 辦法)
找到報(bào)錯(cuò)點(diǎn):
查詢(xún) man 手冊(cè),看看是不是能找到有幫助的東西:
man pthread_attr_setstacksize
打印出解釋?zhuān)?/p>
ERRORS pthread_attr_setstacksize() can fail with the following error:
EINVAL The stack size is less than PTHREAD_STACK_MIN (16384) bytes.
On some systems, pthread_attr_setstacksize() can fail with the error EINVAL if stacksize is not a multiple of the system page size.
翻譯上面的話,可能會(huì)產(chǎn)生這個(gè)錯(cuò)誤:
- EINVAL 堆棧大小小于 PTHREAD_STACK_MIN(16384) 字節(jié)。
- 在某些系統(tǒng)上,如果 stacksize 不是系統(tǒng)頁(yè)面大小的倍數(shù), pthread_attr_setstacksize() 可能會(huì)失敗,并顯示錯(cuò)誤 EINVAL
查詢(xún) linux 報(bào)錯(cuò)碼含義, 得知錯(cuò)誤碼 22 果然和 man 手冊(cè)中說(shuō)的一致,是參數(shù)有問(wèn)題。
第一次嘗試:擴(kuò)大線程棧到上面說(shuō)的 16384 ,但還是報(bào)錯(cuò)
根據(jù)經(jīng)驗(yàn),查看最小頁(yè)大小,發(fā)現(xiàn)是 16k , 而 x86 架構(gòu)是 4K ,原來(lái)用的 20K 是不對(duì)齊的,怪不得創(chuàng)建不出來(lái)線程。
依次嘗試, 最終發(fā)現(xiàn) 10*16K 子線程成功創(chuàng)建。
但是不準(zhǔn)確,按其說(shuō)法,應(yīng)該是設(shè)置 PAGESIZE 的整數(shù)倍都行,懷疑其對(duì)最小值有要求。c++ 的頭文件在 /usr/include 目錄下面, PTHREAD_STACK_MIN 是一個(gè)常量,估計(jì)里面會(huì)有定義,嘗試查找
$ grep -rl PTHREAD_STACK_MIN *
bits/local_lim.h
pthread.h
還真讓我找到了, 根據(jù)英文注釋?zhuān)辽僖獌蓚€(gè) 64K 作為線程棧,才能跑起一個(gè)線程。
我發(fā)現(xiàn)程序雖然正常運(yùn)行,但是部分功能不正常,經(jīng)過(guò)查看日志發(fā)現(xiàn),有一個(gè)線程只執(zhí)行了一半就卡住了。
經(jīng)過(guò)查看日志可以定位出是哪個(gè)線程卡住,如果從日志看不出來(lái)也沒(méi)關(guān)系。可以使用 pstack 進(jìn)程號(hào) 看一些進(jìn)程堆棧。
查看進(jìn)程 pid:
ps -ef |grep 進(jìn)程名
使用 gdb 查看是否出現(xiàn)問(wèn)題,兩個(gè)重要命令:
- gdb attach {pid} #查看正在運(yùn)行程序的棧
- info thread #進(jìn)入以后使用,查看線程信息
找到錯(cuò)誤位置,出現(xiàn)了 fgets() 和 read() 函數(shù),懷疑是此處出現(xiàn)問(wèn)題。
懷疑 1:_LINE_LENGTH 1024 長(zhǎng)度太短,接受命令返回之后超過(guò)了數(shù)組本身的長(zhǎng)度,覆蓋了未知的內(nèi)存。
這種情況我以前遇到過(guò),表現(xiàn)應(yīng)該是程序直接就崩潰了。
懷疑 2:執(zhí)行命令的時(shí)候卡了,導(dǎo)致后面的程序沒(méi)有執(zhí)行。
根據(jù) gdb 打印出來(lái)的參數(shù),執(zhí)行 linux 命令進(jìn)行測(cè)試,果然是卡在這了!
再次使用 pstree -p {pid} 查看,確實(shí)主線程,調(diào)用了 linux 命令卡住。
接下來(lái)解決卡命令的問(wèn)題。
解決 1:加 timeout 處理空返回。下面是示例命令,并不是我使用的命令。
timeout 5 ls -al
代表超過(guò) 5 秒返回。
解決 2:定位為什么這個(gè) linux 命令會(huì)卡住。
strace ls -al
直到解決為止。希望對(duì)大家也有幫助。哪里寫(xiě)的不好大家可以評(píng)論區(qū)留言 大家一起學(xué)習(xí)交流一下