killall为什么有时候会找不到进程?
?
前言
在Linux下有很多命令用于殺死進程,它們可以用于不同的場景,例如通過進程名殺死進程,通過pid殺死進程。這些方法我不準備一一列舉,本文想說明的一個問題是,為什么明明通過ps找到了進程,但是通過killall卻說找不到呢?如果你沒有遇到過這樣的問題?那你更要注意了!
killall簡介
與kill不同的是,killall可以根據進程名來殺死進程,不像kill,可能先需要使用ps(可以參考《ps命令實例詳解》)找到進程id,然后發送信號,就像下面這樣:
$?ps?-ef|grep?hello root??????15530??6335??0?14:55?pts/4????00:00:00?./hello $?kill?-9?15530這樣進程就被我們殺死了,我們可以直接使用killall:
$?killall?hello是不是覺得方便多了?
而且由于killall是根據名稱殺死進程,因此如果當前運行著大量的hello程序,那么可以一次性殺死所有hello程序。
除此之外,它還有很多參數,例如忽略大小寫,根據模式匹配進程名,殺死某個時間的進程等等,這里就不詳解介紹了,有興趣的可以查看man killall手冊。
今天這里想要說明的是一種killall失效的情況。
killall失效了?
我寫了一個自己的hello程序,然后嘗試使用killall殺死正在運行的hello程序。
$??killall?hello hello:?no?process?found什么?竟然說找不到?一個ps丟過來:
$?ps?-ef|grep?hello root??????15765??6335??0?15:05?pts/4????00:00:00?./hello所以killall你到底行不行?
為何
為了找出killall失效的原因,我們必須知道它到底是如何通過進程名找到進程的。
這個時候就需要祭出我們的神器strace了,看看killall殺死一個普通進程到底做了哪些事情:
打印結果很多,我只提取了部分,可以看到的是,killall會去proc文件系統(proc文件系統可以參考《Linux中不可錯過的信息寶庫》)下查找各個進程id下的stat文件和cmdline,stat文件是怎樣的呢?我們隨便找一個看看:
$?cat?/proc/16131/stat? 16131?(hello)?S?6335?16131?6335?34820?16131?1077936128?70?0?0?0?0?0?0?0?20?0?1?0?2465163?4321280?194?18446744073709551615?4194304?4196092?140734969955328?0?0?0?0?0?0?1?0?0?17?0?0?0?0?0?0?6295056?6295608?19099648?140734969962804?140734969962812?140734969962812?140734969966576?0我們不要被這么多內容嚇到了,可以明顯看到的是,里面有hello啊。至此我們可以猜測,killall命令會去讀取進程在proc文件系統中的stat文件里的名字。那么如果這么名字和你要殺死的進程對不上不就找不到了嗎?
至此,想必你已經明白前面問題的原因了。
如何給自挖坑
那么怎樣修改stat中顯示的名字呢?我們可以使用prcl函數,話不多少,直接看示例代碼:
//來源:公眾號【編程珠璣】 //作者:守望先生 #include<stdio.h> #include<sys/prctl.h> #include<unistd.h> int?main(void) {prctl(PR_SET_NAME,"bianchengzhuji");?sleep(100);//防止進程立即退出,便于觀察return?0; }這個時候再編譯運行程序查看stat和status中的名字:
$?gcc?-o?hello?hello.c $?cat?/proc/pid/stat??#這里的pid換成示例的進程id 16441?(bianchengzhuji)?S?6335?16441?6335?34820?16441?1077936128?69?0?0?0?0?0?0?0?20?0?1?0?2535513?4321280?156?18446744073709551615?4194304?4196188?140724949606512?0?0?0?0?0?0?1?0?0?17?3?0?0?0?0?0?6295056?6295616?31719424?140724949614900?140724949614908?140724949614908?140724949618672?0 $?more?/proc/pid/status Name:????bianchengzhuji Umask:????0002 State:????S?(sleeping) Tgid:????16441 Ngid:????0 Pid:????16441 PPid:????6335是不是發現名字變了呢?雖然進程名還是hello,但是killall已經找不到它了,不過:
$?killall?bianchengzhuji還是可以的。
為什么會出現這種情況呢?
想象一下,你們公司內部不想重復造輪子,搞了一套開發框架,main函數在框架里寫好了,通過庫的形式給你們使用,可能名字早就定好了。或者是多線程程序,它的名字是main。
但是,這里需要特別注意的是,如果名字超過了15個字符,在stat和status文件中看到的將會看到被截斷的名字。
玩點刺激的
既然看到這里了,不如再玩點刺激的。
看看下面的代碼:
//來源:公眾號【編程珠璣】 #include<stdio.h> #include<string.h> #include<unistd.h> int?main(int?argc,char?*argv[]) {strncpy(argv[0],"bianchengzhuji",sizeof("bianchengzhuji"));sleep(100);return?0; }是不是發現和前面例子的main函數不一樣?參考這里(《C語言的main到底該怎么寫》)
這個時候你去編譯運行:
然后嘗試使用ps去查找進程:
$?ps?-ef|grep?hello root??????17831?17818??0?16:09?pts/26???00:00:00?grep?--color=auto?hello然后你就會驚喜的發現找不到hello進程。
但是使用:
就可以找到。
這種情況下直接改變了程序的命令名,因此ps之類的找不到。
這個時候看命令名是什么呢?
不過這個時候killall還是可以找到它!也就是你可以使用killall hello殺死它。
總結
如果你發現你的程序無法通過killall 進程名的方式殺死的話,不妨看看proc文件系統中這個進程的stat文件或者status文件中的名。
推薦閱讀:
每天都在用printf,你知道變長參數是怎么實現的嗎
幾個命令了解ELF文件的”秘密“
?
首發:公眾號【編程珠璣】
作者:守望先生
ID:shouwangxiansheng
關注公眾號【編程珠璣】,獲取更多Linux/C/C++/算法/計算機基礎/工具等原創技術文章。后臺免費獲取經典電子書和視頻資源
總結
以上是生活随笔為你收集整理的killall为什么有时候会找不到进程?的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 妻子是前世渡你的人
- 下一篇: Ubuntu16.04安装后要做的一些事