孤兒進程
父進程先于子進程結束,則子進程成為孤兒進程,子進程的父進程成為init
進程,則稱init
進程領養孤兒進程。現在好像是用戶進程中的system
進程。
僵尸進程
進程終止,父進程不進行回收,自己成殘留資源(PCB)存放在內核中,變成僵尸進程。
子進程死亡以后會將自己占用的內存(4G)釋放,但是會將死亡信息放在自己的PCB中,希望父進程調用得到子進程的死亡信息以后再清除PCB。需要注意的是僵尸進程是不能使用kill
命令清除掉的,因為kill
命令知識用來終止進程的,而僵尸進程已經終止。這就要求我們手動回收子進程。
這里的僵尸進程特別指的是父進程沒有結束而子進程已經結束,如果父進程結束就算我們不手動回收也會自動回收(實際過程是父進程結束以后沒有回收的子進程變成孤兒進程被init
進程或者system
進程回收)
wait函數回收子進程
一個進程在終止時會關閉所有的文件描述符,釋放在用戶空間分配的內存,但它的PCB還保留著,內核在其中保存了一些信息:如果是正常終止則保存著退出狀態,如果是異常終止則保存著導致該進程終止的信號是哪個。這個進程的父進程可以調用wait
或者waitpid
獲取這些信息,然后徹底清除這個進程。
shell下一個進程的退出狀態可以用特殊變量$?
查看,因為shell
是他的父進程,當它終止時shell調用wait
或者waitpid
得到它的退出狀態同時徹底清除掉這個進程。
wait函數可以回收子進程終止信息,該函數有三個功能:
- 阻塞等待子進程退出:如果子進程沒有結束父進程不會干其他的事情
- 回收子進程殘留的
PCB
資源 - 獲取子進程結束狀態(退出原因)
一次wait函數只能清除一個子進程
pid_t wait(int *status);
返回值:如果成功返回子進程ID,如果失敗返回-1
(沒有子進程的話就會報錯)
status保存結束狀態
- 進程正常結束
WIFEXITED(status) 為非0說明是正常退出
WEXITSTATUS(status)如果上面宏為真,使用這個宏獲取進程退出狀態(exit的參數)
- 進程異常終止(收到信號終止,例如段錯誤、總線錯誤、浮點數例外錯誤)
WIFSIGNALED(status) 為非0,說明程序異常終止
WTERMSIG(status)如果上面宏為真使用此宏 取得使得進程終止的那個信號的編號
- 進程處于暫停狀態
WIFSTOPPED(status) 為非0,進程處于暫停狀態
WSTOPSIG(status) 如果上述宏為真,取得使得進程暫停的那個信號的編號
WIFCONTINUED(status) 為真表示進程暫停后已經繼續運行
waitpid函數
一次waitpid函數只能清除一個子進程,和wait
函數類似
pid_t waitpid(pid_t pid,int* status,int options)
第一個參數用于指定需要回收的進程ID,第三個參數可以設置不阻塞回收,即僅僅返回一個狀態
pid
:
- 大于0 表示回收的子進程ID
- -1 表示回收任意子進程(相當于wait)
- 0 回收當前調用
waitpid
一個組的任意子進程,在一般情況下和-1
相同 - <-1 回收指定進程組內的任意子進程,
-進程組ID
,進程組ID可以用ps ajx
查看
options
: - 當參數為
WNOHANG
,非阻塞回收,輪詢查看 - 當參數為
0
的時候,阻塞回收,相當于wait
返回值:
- 成功返回子進程ID
- 失敗返回-1
- 如果輪詢訪問回收子進程的時候子進程沒有結束則返回0
例如:
#include<stdio.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/wait.h>
#include<unistd.h>int main(int argc, char* argv[])
{int n=5;if(argc>2){printf("too many arguments\n");exit(1);}else if(argc==2){n = atoi(argv[1]);}int pi;pid_t p,q;for(pi=0;pi<n;++pi){p=fork();if(0 == p){break;}else if(3 == pi){q = p;}}if(n==pi){printf("I am parent,pid = %d\n",getpid());//刪除單個子進程//waitpid(q,NULL,0);//循環刪除子進程//while(-1!=waitpid(-1,NULL,0));//非阻塞刪除子進程pid_t tid;do{tid=waitpid(-1,NULL,WNOHANG);}while(tid != -1);printf("OK\n");while(1);}else{printf("I am child,pid = %d\n",getpid());}return 0;
}