一 相關知識:
1 ——殭屍進程:
(1)殭屍進程:
@ 僵死狀態是一個比較特殊的狀態。當進程退出並且父進程沒有讀取到子進程退出的返回代碼時就會產生殭屍進程;
@ 殭屍進程會以終止狀態保持在進程表中,並且會在一直等待父進程讀取退出狀態代碼;
@ 只要子進程退出,父進程還在運行,但父進程沒有讀取子進程狀態,子進程進入殭屍狀態。
(2)殭屍進程危害:
@ 進程的退出狀態必須被維持下去,因爲他要告訴關心它的進程(父進程),你交給我的任務,我辦的怎麼樣了;可父進程如果一直不讀取,那個進程就一直處於Z(殭屍)狀態;
@ 維護推出狀態本身就是要用數據維護,也屬於進程基本信息,所以保存在tast_struct(PCB)中,也就是說,Z狀態一直不退出,PCB一直都要維護;
@ 那一個父進程創建了很多子進程,就是不回收,就會造成內存資源的浪費;因爲數據結構對象本身就要佔用內存;
(3)殭屍進程的避免
# 父進程通過wait和waitpid等函數等待子進程結束,這會導致父進程掛起。
# 如果父進程很忙,那麼可以用signal函數爲SIGCHLD安裝handler,因爲子進程結束後, 父進程會 收到該信號,可以在handler中調用wait回收。
# 如果父進程不關心子進程什麼時候結束,那麼可以用signal(SIGCHLD,SIG_IGN) 通知內核,自己 對子進程的結束不感興趣,那麼子進程結束後,內核會回收, 並不再給父進程發送信號。
# 還有一些技巧,就是fork兩次,父進程fork一個子進程,然後繼續工作,子進程fork一 個孫進程 後退出,那麼孫進程被init接管,孫進程結束後,init會回收。不過子進程的回收 還要自己做。
————————————————————————————————————
2 ——孤兒進程
@ 父進程如果提前退出,那麼子進程就稱之爲“孤兒進程”;
@ 孤兒進程被1號init進程領養,當然要有init進程回收。
孤兒進程:一個父進程退出,而它的一個或多個子進程還在運行,那麼那些子進程將成爲孤兒進程。孤兒進程將被init進程(進程號爲1)所收養,並由init進程對它們完成狀態收集工作。孤兒進程是沒有父進程的進程,孤兒進程這個重任就落到了init進程身上,init進程就好像是一個民政局,專門負責處理孤兒進程的善後工作。每當出現一個孤兒進程的時候,內核就把孤 兒進程的父進程設置爲init,而init進程會循環地wait()它的已經退出的子進程。這樣,當一個孤兒進程淒涼地結束了其生命週期的時候,init進程就會代表黨和政府出面處理它的一切善後工作。因此孤兒進程並不會有什麼危害
**
二 模擬代碼:
**
1 殭屍進程
makefile文件:
jiangshi:jiangshi.c
gcc jiangshi.c -o jiangshi
.PHONY:clean
clean:
rm -f jiangshi
jiangshi.c文件
#include<stdio.h>
#include<stdlib.h>
int main()
{
pid_t id = fork();
if(id < 0)
{
perror("fork");
return 1;
}
else if(id > 0) //father
{
printf("father pid is %d\n",getpid());
sleep(10);
}
else //child
{
printf("child pid is %d\n",getpid());
sleep(3);
exit(EXIT_SUCCESS);
}
return 0;
}
結果:
————————————————————————————————————
2 孤兒進程
makefile文件
guer:guer.c
gcc guer.c -o guer
.PHONY:clean
clean:
rm -f guer
guer.c文件
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
int main()
{
pid_t id = fork();
if(id == -1)
{
perror("fork");
}
else if(id == 0) //child
{
printf("I am child,pid: %d,father pid is %d\n",getpid(),getppid());
sleep(5);
}
else //father
{
printf("I am father,pid: %d,child pid is %d\n",getpid(),getppid());
sleep(3);
exit(0);
}
return 0;
}
結果: