5、子进程回收(wait和waitpid)

一个进程在终止时会关闭所有文件描述符,释放在用户空间分配的内存,但它的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;
}

5、子进程回收(wait和waitpid)5、子进程回收(wait和waitpid) C/C++菜鸡 发布了49 篇原创文章 · 获赞 3 · 访问量 765 私信 关注
上一篇:Android开发中用到的第三方框架汇总


下一篇:wait,waitpid的学习使用