如何編寫unix 程序防止殭屍進程的出現?


#include &
#include &

int main()
{
int pid = fork();
if ( pid &> 0 )
{
while ( 1 )
{
sleep(3);
}
}
else if ( pid == 0 )
{
printf("i die
");
}
}

上述程序中,fork了一個子進程,並且子進程很快就退出。父進程持續進行sleep,這樣子進程就變成了殭屍進程。利用ps命令可以清晰的看到這一點。

[leconte@localhost ~]$ps axu |greptest
leconte 32600 0.0 0.0 1516 268 pts/1 S+ 20:43 0:00 ./test
leconte 32601 0.0 0.0 0 0 pts/1 Z+ 20:43 0:00 [test] &
leconte 32603 0.0 0.1 5024 668 pts/2 R+ 20:43 0:00 grep test

Z+代表進程32601是殭屍進程。

殭屍進程和孤兒進程的區別是,孤兒進程是子進程還在運行,而父進程掛了,子進程被init進程收養。殭屍進程是父進程還在運行但是子進程掛了,但是父進程卻沒有使用wait來清理子進程的進程信息,導致子進程雖然運行實體已經消失,但是仍然在內核的進程表中佔據一條記錄,這樣長期下去對於系統資源是一個浪費。

這時候殺掉父進程即可清理該殭屍進程。當然這並非長久之計,根本的辦法是從代碼上進行控制,防止類似的事情再發生。常見的方法無非是處理父進程的SIGCHLD信號,在信號處理函數里用wait或者waitpid等函數進行處理。更改後的代碼如下:

#include &
#include &
#include &

void* handler(int sig)
{
int status;

if (waitpid(-1, status, WNOHANG) &>= 0)
{
printf("child is die,i know
");
}
}

int main()
{
signal(SIGCHLD,handler);
int pid = fork();
if ( pid &> 0 )
{
while ( 1 )
{
sleep(3);
}
}
else if ( pid == 0 )
{
printf("i die
");
}
}

這樣更改後執行的輸出如下:

[leconte@localhost test]$ ./test
i die
child is die,i know

可見父進程已經成功地處理了子進程的退出信號,子進程徹徹底底的消失了。

------------------------分割線----------------------

unistd.h 是 C 和 C++ 程序設計語言中提供對 POSXI 操作系統API的訪問功能的頭文件的名稱。該頭文件由 POSIX.1 標準(單一UNIX規範的基礎)提出,故所有遵循該標準的操作系統和編譯器均應提供該頭文件(如 Unix 的所有官方版本,包括 Mac OS X、Linux等)。

對於類 Unix 系統,unistd.h 中所定義的介面通常都是大量針對系統調用的封裝(英語:wrapper functions),如 fork、pipe 以及各種 I/O原語(read、write、close 等等)。

類似於 Cygwin 和 MinGW 的 Unix 兼容層也提供相應版本的 unistd.h。


進程結束了不回收才會有殭屍

讓爹wait()了就好 沒爹的進程會被init認兒子然後回收


剛看過,怒答一發!

如果父進程不需要通過pid管理子進程,那麼fork一次,然後wait,再讓fork出來的子進程fork一個孫子進程出來,然後子進程自殺,然後父進程通過wait回收子進程,此時孫子進程直接被init進程收養,死了自動回收。

如果需要通過pid管理,那隻能用waitpid之類的調用來人為回收結束的子進程


我覺得要產生一個殭屍進程才需要刻意用程序去實現!


SIG_IGN黨飄過~~~我就好奇為啥不一開始就把這種臟活交給init去搞


推薦閱讀:

有中文計算機高級語言嗎?
C語言int x=4294967295;怎麼改代碼才能結果顯示為「4294967295」?
為什麼不建議用 try catch?
malloc出錯?

TAG:操作系統 | 編程 | UNIX環境高級編程書籍 | 殭屍進程zombie |