wait/waitpid

一个进程在终止时会关闭所有文件描述符,释放在用户空间分配的内存,但它的 PCB还保留着,内核在其中保存了一些信息:如果是正常终止则保存着退出状态,如果是异常终止则保存着导致该进程终止的信号是哪个。这个进程的父进程可以调用 wait 或 waitpid 获取这些信息,然后彻底清除掉这个进程。我们知道一个进程的退出状态可以在 Shell 中用特殊变量$?查看,因为 Shell 是它的父进程,当它终止时 Shell 调用 wait 或 waitpid 得到它的退出状态同时彻底清除掉这个进程。

wait函数原型及作用

作用:

1、阻塞等待子进程退出

2、回收子进程残留资源

3、获取子进程结束状态(退出原因)。

原型:
  • pid_t wait (int *status);

  • 成功:清理掉的子进程 ID;失败:-1 (没有子进程)

宏函数判断终止原因

WIFEXITED(status)宏判断为真 ---> 表示程序正常退出

WEXITSTATUS(status) 上一个宏判断为真 则返回状态值

WIFSIGNALED(status) 宏判断为真 ---> 表示程序异常退出

WTERMSIG(status) 上一个判断为真,则返回状态值

wait和宏函数配套使用实例
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>

int main()
{
    pid_t pid,wpid;
    int status;
    pid =fork();
    if(pid==0)
    {
        printf(" i am child,my id is%d\n",getpid());
        printf("child die\n");
        return 73;
    }
    else if(pid>0)
    {
        wpid=wait(NULL);//不关心怎么结束的
        wpid = wait(&status);//等待子进程结束
        if(wpid==-1)
        {
            perror("wait error");
            exit(1);
        }
        if(WIFEXITED(status))//判断 子进程正常退出判断
        {
            printf("child exit with%d\n",WEXITSTATUS(status));
            printf("------parent  finish\n");
        }
        if(WIFSIGNALED(status))//判断 子进程异常退出判断
        {
            printf("child exit with%d\n",WTERMSIG(status));
        }
    }
    else
    {
        perror("fork");
        return 1;
    }
    
}

waitpid函数原型及作用

作用

作用同 wait,但可指定 pid 进程清理,可以不阻塞。

原型:
  • pid_t waitpid ( pid_t pid, int *status, in options );

  • 成功:返回清理掉的子进程 ID; 失败:-1(无子进程)

参数:

pid : 指定回收的子进程pid

status : (传出) 回收进程的状态

options : WNOHANG 指定回收方式为 ---> 非阻塞

等待集合的成员是由参数 pid 来确定

pid : > 0 回收指定ID的子进程

-1 回收任意子进程(相当于wait)

0 回收和当前调用waitpid一个组的所有子进程

< -1 回收指定进程组内的任意子进程

返回值:

>0 如果成功,则为子进程的PID,

0 : 如果options为WNOHANG,则返回0,且子进程正在运行

-1: 如果发生其他错误,则返回-1

注意
  • 一次 wait 或 waitpid 调用只能清理一个子进程,清理多个子进程应使用循环。

  • 二者等价 waitpid (-1, &status, 0 ) == wait ( &status )

实例一:waitpid回收指定子进程
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/wait.h>
#include <pthread.h>
int main(int argc, char *argv[])
{
    int i;
    pid_t pid, wpid, tmpid;
    for (i = 0; i < 5; i++) {       
        pid = fork();  // for循环在父进程中执行   父进程返回子进程的ID  子进程返回 0 
        if (pid == 0) {   // pid=0,子进程退出   循环期间, 子进程不 fork 
            break;
        }
        if (i == 2) {
            tmpid = pid;    //子进程pid
            printf("--------pid = %d\n", tmpid);
        }
    }

    if (5 == i) {       // 父进程, 从 表达式 2 跳出
//      sleep(5);
        //wait(NULL);                           // 一次wait/waitpid函数调用,只能回收一个子进程.
        //wpid = waitpid(-1, NULL, WNOHANG);    //回收任意子进程,没有结束的子进程,父进程直接返回0 
        //wpid = waitpid(tmpid, NULL, 0);       //指定一个进程回收, 阻塞等待
        printf("i am parent , before waitpid, pid = %d\n", tmpid);
        //wpid = waitpid(tmpid, NULL, WNOHANG);   //指定一个进程回收, 不阻塞
        wpid = waitpid(tmpid, NULL, 0);         //指定一个进程回收, 阻塞回收
        if (wpid == -1) {
            perror("waitpid error");
            exit(1);
        }
        printf("I'm parent, wait a child finish : %d \n", wpid);
    } else {            // 子进程, 从 break 跳出
        sleep(i);
        printf("I'm %dth child, pid= %d\n", i+1, getpid());
    }
    return 0;
}
实例二:waitpid回收指定子进程(错误写法)
这段代码从结果上可以看出做不到回收指定的进程。两段代码的区别在于子进程id的存放的方式。
在这段代码中,我们在子进程中做了pid = getpid();父子进程资源不共享导致的是父进程不知道这个pid的值。
而在上一段代码中,我们直接通过 pid = fork();tmpid = pid;这样的方式在父进程中成功保存子进程的进程号。

https://www.bilibili.com/video/BV1KE411q7ee/?p=97&spm_id_from=pageDriver&vd_source=d239c7cf48aa4f74eccfa736c3122e65

//指定回收一个子进程错误示例
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/wait.h>
#include <pthread.h>
int main(int argc, char *argv[])
{
    int i;
    pid_t pid, wpid;
    for (i = 0; i < 5; i++) {       
        if (fork() == 0) {       // 循环期间, 子进程不 fork 
            if (i == 2) {
                 pid = getpid();  // 保存在子进程
                 printf("------pid = %d\n", pid);
            }
            break;
        }
    }
    if (5 == i) {       // 父进程, 从 表达式 2 跳出
        sleep(5);      
        printf("------in parent , before waitpid, pid= %d\n", pid);
        wpid = waitpid(pid, NULL, 0);  //指定一个进程回收
        if (wpid == -1) {
            perror("waitpid error");
            exit(1);
        }
        printf("I'm parent, wait a child finish : %d \n", wpid);
    } else {            // 子进程, 从 break 跳出
        sleep(i);
        printf("I'm %dth child, pid= %d\n", i+1, getpid());//用户空间释放,内核PCB残留
    }
    return 0;
}
实例三:waitpid 回收全部子进程
// 回收多个子进程

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


int main(int argc, char *argv[])
{
    int i;
    pid_t pid, wpid;

    for (i = 0; i < 5; i++) {       
        pid = fork();
        if (pid == 0) {       // 循环期间, 子进程不 fork 
            break;
        }
    }

    if (5 == i) {       // 父进程, 从 表达式 2 跳出
    
      while((wpid=waitpid(-1,NULL,0))>0)
      {
          printf("I'm parent,wait a child finish:%d\n",wpid);
      }
      
    } else {            // 子进程, 从 break 跳出
        sleep(i);
        printf("I'm %dth child, pid= %d\n", i+1, getpid());
    }

    return 0;
}

暴力回收子进程

kill -9 父进程号
查看 kill -l
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值