Linux模擬實(shí)現(xiàn)僵尸進(jìn)程
發(fā)布時(shí)間:2021-04-26 14:59:14
Linux模擬實(shí)現(xiàn)僵尸進(jìn)程
Z(zombie)-僵尸進(jìn)程
僵死狀態(tài)(Zombies) 是一個(gè)比較特殊的狀態(tài)。當(dāng)進(jìn)程退出并且父進(jìn)程沒有讀取到子進(jìn)程退出的返回代碼是就會(huì)產(chǎn)生僵尸進(jìn)程。
僵尸進(jìn)程會(huì)以終止?fàn)顟B(tài)保存在進(jìn)程表中,并且會(huì)一直等待父進(jìn)程讀取退出狀態(tài)代碼。
所以,只要子進(jìn)程退出,父進(jìn)程還在執(zhí)行,但父進(jìn)程沒有讀取子進(jìn)程狀態(tài),子進(jìn)程進(jìn)入Z狀態(tài)
模擬實(shí)現(xiàn)僵尸進(jìn)程
//模擬實(shí)現(xiàn)僵尸進(jìn)程
int main()
{
pid_t pid;
pid = fork();
if(pid == -1)
{
perror("創(chuàng)建失敗");
}
if(pid == 0)//孩子進(jìn)程
{
sleep(3);
printf("孩子進(jìn)程死亡\n");
}
else if(pid >0)//父進(jìn)程
{
int times = 10;
while(times--)
{
printf("父進(jìn)程:%d\n",times);
sleep(1);
}
printf("父進(jìn)程死亡\n");
}
return 0;
}
測(cè)試結(jié)果
整個(gè)程序的調(diào)用過程如上,分別在1,2,3處調(diào)用了查看進(jìn)程命令,1處表示程序正常執(zhí)行,2處表示孩子進(jìn)程已死亡,變成孤兒進(jìn)程,3處表示父進(jìn)程死亡并退出。
這是第一次查看進(jìn)程的結(jié)果,紅色的方框表示本進(jìn)程的PID,第一個(gè)黃色的方框表示父進(jìn)程的PID,第二個(gè)黃色的框表示進(jìn)程名,由圖可知,第二個(gè)進(jìn)程的PID為3340,他的父進(jìn)程為3339,恰好是第一個(gè)進(jìn)程的PID,由此可知第二個(gè)進(jìn)程是第一個(gè)進(jìn)程的子進(jìn)程,這時(shí)父子進(jìn)程同時(shí)在運(yùn)行。
此時(shí)表示孩子進(jìn)程已死亡,但是父進(jìn)程還在運(yùn)行,子進(jìn)程成為僵尸進(jìn)程
最后父進(jìn)程退出,系統(tǒng)回收資源,并將子進(jìn)程的資源同時(shí)回收,進(jìn)程消失。
僵尸進(jìn)程的產(chǎn)生
一個(gè)進(jìn)程調(diào)用exit命令結(jié)束自己生命的時(shí)候,其實(shí)它并沒有真正的被銷毀,而是留下一個(gè)稱為“僵尸進(jìn)程”的數(shù)據(jù)結(jié)構(gòu)。這時(shí)它已經(jīng)放棄了幾乎所有內(nèi)存空間,沒有任何可執(zhí)行代碼,也不能被調(diào)度,僅僅在進(jìn)程列表中保留一個(gè)位置(它的內(nèi)核棧還駐留在內(nèi)存中),記載該進(jìn)程的退出狀態(tài)等有用的信息供其它進(jìn)程收集。進(jìn)程的狀態(tài)變成EXIT_ZOMBIE,并且向父進(jìn)程發(fā)送SIGCHLD信號(hào),Linux默認(rèn)是忽略該信號(hào)的,父進(jìn)程可以顯示安裝該信號(hào),在信號(hào)處理函數(shù)中調(diào)用wait或waitpid函數(shù)等待子進(jìn)程結(jié)束并將其徹底清除。如果父進(jìn)程沒有這么做的話,子進(jìn)程就淪為僵尸進(jìn)程了。但是在父進(jìn)程死掉后,它的所有進(jìn)程都會(huì)過繼給init進(jìn)程,init進(jìn)程會(huì)周期性的去調(diào)用wait系統(tǒng)調(diào)用來清除它的僵尸孩子。
僵尸進(jìn)程的危害
少數(shù)的僵尸進(jìn)程并不會(huì)對(duì)系統(tǒng)的性能有什么影響,但是由于Linux系統(tǒng)對(duì)運(yùn)行的進(jìn)程數(shù)量是有限制的,所以如果產(chǎn)生的僵尸進(jìn)程過多,占用了可用的進(jìn)程號(hào),這將會(huì)導(dǎo)致新的進(jìn)程無法生成。
怎么避免僵尸進(jìn)程
(1)創(chuàng)建進(jìn)程的時(shí)候調(diào)用兩次fork,而且使緊跟的子進(jìn)程直接退出,這樣孫子進(jìn)程成為孤兒進(jìn)程,init進(jìn)程將負(fù)責(zé)清除這個(gè)孤兒進(jìn)程。
(2)在Linux下可以簡(jiǎn)單地將SIGCHLD信號(hào)的操作設(shè)為SIG_IGN,這樣內(nèi)核在子進(jìn)程結(jié)束時(shí)不會(huì)產(chǎn)生僵尸進(jìn)程。在SVR4中,如果調(diào)用signal或sigset將SIGCHLD的配置設(shè)置為忽略,也不會(huì)產(chǎn)生僵尸進(jìn)程。
(3)調(diào)用wait或waitpid等待子進(jìn)程結(jié)束,收集僵尸進(jìn)程留下的信息,同時(shí)使僵尸進(jìn)程徹底消失。
(注:不能使用kill 后接SIGKILL信號(hào)這樣的命令像殺死普通進(jìn)程一樣殺死僵尸進(jìn)程,因?yàn)榻┦M(jìn)程是已經(jīng)死掉的進(jìn)程,它不能再接收任何信號(hào)。)
想要了解更多軟件相關(guān)知識(shí)、提升自我,就來盛圖科技吧!
- 上一篇:軟件測(cè)試的基本問題
- 下一篇:OpenCV是什么?