一个进程在终止时会关闭所有文件描述符,释放在用户空间分配的内存,但它的PCB还保留着,内核在其中保存了一些信息:如果是正常终止则保存着退出状态,如果是异常终止则保存着导致该进程终止的信号是哪个。这个进程的父进程可以调用wait或waitpid获取这些信息,然后彻底清除掉这个进程。我们知道一个进程的退出状态可以在Shell中用特殊变量$?查看,因为Shell是它的父进程,当它终止时Shell调用wait或waitpid得到它的退出状态同时彻底清除掉这个进程。
1、wait函数
1>、该函数有三个功能:
① 阻塞等待子进程退出
② 回收子进程残留资源
③ 获取子进程结束状态(退出原因)。
函数原型:pid_t wait(int *status);
返回值:成功:清理掉的子进程ID;失败:-1 (没有子进程)
2>、当进程终止时,操作系统的隐式回收机制会:
1.关闭所有文件描述符
2.释放用户空间分配的内存。内核的PCB仍存在。其中保存该进程的退出状态。(正常终止→退出值;异常终止→终止信号)
3>、wait函数传出参数status来保存进程的退出状态。借助宏函数来进一步判断进程终止的具体原因。宏函数可分为如下三组:
1. WIFEXITED(status) 为非0 → 进程正常结束
WEXITSTATUS(status) 如上宏为真,使用此宏 → 获取进程退出状态 (exit的参数)
2.WIFSIGNALED(status) 为非0 → 进程异常终止
WTERMSIG(status) 如上宏为真,使用此宏 → 取得使进程终止的那个信号的编号。
3.WIFSTOPPED(status) 为非0 → 进程处于暂停状态
WSTOPSIG(status) 如上宏为真,使用此宏 → 取得使进程暂停的那个信号的编号。
WIFCONTINUED(status) 为真 → 进程暂停后已经继续运行
注意:前两组最为重要
2、wait函数的例子
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
int main()
{
int status;
pid_t pid, wpid;
pid = fork();
if(pid == 0)
{
printf("I'm child, pid =%d, going to sleep 10s\n", getppid());
sleep(3);
printf("---------------------clild die-------------------\n");
exit(50);
}else if(pid > 0)
{
wpid = wait(&status);
if(wpid == -1)
{
perror("wait error");
exit(1);
}
if(WIFEXITED(status)) //对子进程结束返回的值进行判断
{
printf("child exit with %d\n", WEXITSTATUS(status));
}
if(WIFSIGNALED(status)) //对子进程因信号死亡进行判断
{
printf("child killed by %d\n", WTERMSIG(status));
}
while(1){
printf("I'm parent, pid =%d, myson pid=%d\n", getpid(), pid);
sleep(1);
}
}else if(pid < 0)
{
perror("fork error");
exit(1);
}
return 0;
}
3、waitpid函数
同wait,但可指定pid进程清理,可以不阻塞。
函数原型:pid_t waitpid(pid_t pid, int *status, in options);
返回值:成功:返回清理掉的子进程ID;失败:-1(无子进程); 返回0:参3为WNOHANG,且子进程正在运行。
特殊参数和返回情况:
参数pid:
> 0 回收指定ID的子进程
-1 回收任意子进程(相当于wait)
0 回收和当前调用waitpid一个组的所有子进程
< -1 回收指定进程组内的任意子进程
主要用的是 >0 和 -1。
注意:一次wait或waitpid调用只能清理一个子进程,清理多个子进程应使用循环。
4.、waitpid函数的例子
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/wait.h>
int main(void)
{
pid_t pid, pid2, wpid;
int flg = 0;
pid = fork();
pid2 = fork();
if(pid == -1){
perror("fork error");
exit(1);
} else if(pid == 0){ //son
printf("I'm process child, pid = %d\n", getpid());
sleep(5);
exit(4);
} else { //parent
do {
wpid = waitpid(pid, NULL, WNOHANG);
//wpid = wait(NULL);
printf("---wpid = %d--------%d\n", wpid, flg++);
if(wpid == 0){
printf("NO child exited\n");
sleep(1);
}
} while (wpid == 0); //子进程不可回收
if(wpid == pid){ //回收了指定子进程
printf("I'm parent, I catched child process,"
"pid = %d\n", wpid);
} else {
printf("other...\n");
}
}
return 0;
}
C/C++菜鸡
发布了49 篇原创文章 · 获赞 3 · 访问量 765
私信
关注