子进程回收函数 wait 与 waitpid 用法详解

子进程回收

0. 背景

进程在终止时会关闭所有文件描述符、释放在用户区分配的内存,但是内核区该进程的进程控制块(PCB)仍被保留用于保存一些信息。

  • 如果程序正常退出,PCB中保存的则是退出状态(exit() 函数的参数)。

  • 如果程序是异常退出,PCB中保存的则是导致程序终止的信号

  • 该进程的**父进程可以调用 waitwaitpid 函数获取PCB 中保存的信息**,并彻底清除该进程

1. wait 函数

1.1 函数原型

#include <sys/types.h>
#include <sys/wait.h>

pid_t wait(int *status)

1.2 函数功能

父进程调用 wait 函数可以获得子进程终止信息,并且彻底清除子进程。具体功能如下:

  • 阻塞父进程,等待子进程退出
  • 获取子进程退出状态信息
  • 回收子进程资源

1.3 函数参数

  • @param: status是一个传出参数,应定义变量后传入变量地址,函数可以通过该参数传出子进程PCB中的信息。查看具体信息方法见1.5小节。

1.4 函数返回值

  • 成功:返回被终止子进程的进程ID
  • 失败:返回 -1

1.5 使用宏获取传出参数所携带的状态信息

如果 wait 函数的实参非 NULL,而是 int 的实参指针,wait函数会将子进程状态信息通过实参传出,通过系统提供的宏可以得知参数所携带的信息。

  • WIFEXITED(status): 子进程如果是通过如下:exit()函数、_exit()main 函数 return方式正常结束,该宏返回 true。接下来可以通过 WEXITSTATUS(status) 宏获得进程退出状态(即 exit() 函数的参数)。
  • WIFSIGNALED(status): 如果该宏返回 true则子进程为异常退出,程序异常退出主要因为信号。接下来可以通过 WTERMSIG(status)获取导致进程终止的信号的编号
  • WIFSTOPPED(status): 进程处于暂停状态,则该宏返回true。接下来,WSTOPSIG(status)可以用于获取使进程暂停的那个信号的编号。若WIFCONTINUED(status)true进程暂停后已经开始继续运行

1.6 代码示例

#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>
#include <stdlib.h> // exit

int main(void)
{
    pid_t pid = fork();
    int status = 0;
    if (pid > 0) {
        pid_t wpid = wait(&status);
        if (WIFEXITED(status))
        {
            // 正常退出
            printf("I'm parent, The child process "
					"%d exit normally\n", wpid);
			printf("return value:%d\n", WEXITSTATUS(status));   // WEXITSTATUS 可以获取进程退出状态 (exit 的参数)
            
        } else if (WIFSIGNALED(status)) {
            // 异常退出,即被信号终止为 真
            printf("The child process exit abnormally, "
					"killed by signal %d\n", WTERMSIG(status));//获取信号编号
			
            // 另一个终端 用 kill -9 pid 即可发送杀死信号						
        }
        
    } else if (pid == 0) {
        printf("I am child, my id is:%d\tmy parent id is:%d\n.",getpid(), getppid());
        sleep(2);
    #if 0
        execl("05_abnormal", "05_abnormal", NULL);  // 会触发 8 号信号 因为执行的程序会出现 除零错误
        perror("execl error...");
        exit(-1);
    #endif
        exit(10);
    }
}

2. waitpid 函数

2.1 函数原型

#include <sys/types.h>
#include <sys/wait.h>

pid_t waitpid(pid_t pid, int *status, int options)

2.2 函数功能

wait函数相同,waitpid函数也是用于回收子进程资源获取子进程结束状态信息

2.3 函数参数

  • @param: pid:
    • > 0 : 回收指定 ID 的子进程
    • -1:回收任意子进程,waitpid(-1, status, 0)等价于wait(status)
    • 0: 回收和当前调用 waitpid 函数一个组的所有子进程
    • < -1: 回收指定进程组内的任意子进程
  • @param: status: 是一个传出参数,应定义变量后传入变量地址,函数可以通过该参数传出子进程PCB中的信息
  • @param: options:
    • 0:设置为阻塞状态,阻塞等待子进程结束,对其进行回收。
    • WNOHSNG:设置为不阻塞状态,此时如果没有子进程结束,则直接返回,该参数需要配合轮询方法使用

2.4 函数返回值

  • 成功:返回被终止子进程的进程ID
  • 失败:返回 -1

2.5 使用宏获取传出参数所携带的状态信息

同上文 1.5 节

2.6 代码示例

#include <sys/stat.h>   // waitpid
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>

int main(void)
{
    pid_t cpid, wpid;
    int status;
    int n = 5;
    int i;
    for (i = 0; i < n; i++) {
       cpid = fork();
        if (cpid == -1) {
            perror("fork");
            exit(EXIT_FAILURE);
        } else if (cpid == 0) {
           break;
        } 
    }
    if (n == i) {
        // parent
        sleep(n);
        printf("I am parent, pid is: %d.\n", getpid());
        do
        {
           wpid = waitpid(-1, NULL, WNOHANG);
           if (wpid > 0) {
               n--;
           }
           sleep(1);
        } while (n > 0);
       printf("wait finished.\n");
       
    } else {
        sleep(i);
		printf("I'm %dth child, pid = %d\n", i+1, getpid());
    }

}
  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值