Linux--进程的等待

一.进程等待的必要性
1.如果子进程退出,父亲还在继续执行而且不接收子进程的退出信息,则子进程就会变成僵尸进程。
2.僵尸进程有很多的危害,会造成内存泄露等;
3.僵尸进程无法通过kill -9杀死(因为僵尸进程已经死了,没有办法杀死已经死了的进程);
4.父进程创建子进程会让子进程执行一些任务,我们必须要知道子进程将任务执行的如何,子进程是否正常退出。
5.所以父进程通过进程等待的方式回收子进程的资源,获取子进程的退出信息。

二.进程等待的方式(进程等待有多种方式,主讲下面两种)
1.wait(wait为阻塞等待)
2.waitpid(当waitpid的第三个参数为0时表示阻塞等待,当为WNOHANG时表示非阻塞等待)
注:阻塞等待:一直检测某个条件,条件不满足也要一直等;非阻塞等待:隔一段时间检测某个条件,不满足可以做别的事情。

三.进程等待的方式之wait
1.wait函数原型为:
pid_t wait(int* status)
2.返回值
成功返回被等待进程的pid,失败返回-1
3.参数
(1)输出型参数,用于获取子进程的退出信息,如果不关心子进程的退出信息,则可将参数设置为NULL。
(2)获取子进程的status
①status的低8位用于存放信号信息,当低8位为0时,表示进程正常退出,正常退出就会有退出码,则退出码用次低8位(低8位前面的8位)表示。
②当低8位不为0时,说明该进程异常退出(被信号打断),此时低8位用于存放异常终止信号。
(3)所以调用wait时,先看status的低8位,低8位为0时才看次低8位。
4.测试代码
(1)不关心退出状态(参数为NULL)
#include<stdio.h>                                                                                                                                  
#include<unistd.h>
#include<wait.h>
#include<stdlib.h>

int main()
{
    pid_t pid = fork();
    if(pid == 0)
    {
        //child
        printf("child pid=%d\n",getpid());
        sleep(20);  //子进程睡20秒之后再退出,在这20秒内父进程会一直等待
        exit(1);
    }
    else if(pid > 0)
    {
        //father
        printf("father\n");
        pid_t ret = wait(NULL);
        printf("exitnum %d\n",ret);  //ret为wait的返回值,成功返回子进程的pid
    }
    else
    {
        perror("fork()");
    }
    return 0;
}
运行结果:(刚开始会打印出father和child pid这些内容,过20秒之后会输出exitnum这句话)

(2)参数不为空(即关心子进程的退出状态)
#include<stdio.h>                                                                                                                                  
#include<unistd.h>
#include<wait.h>
#include<stdlib.h>

int main()
{
    pid_t pid = fork();
    if(pid == -1)
    {
        perror("fork()\n");
    }
    else if(pid == 0)
    {
        //child
        printf("child pid:%d\n",getpid());
        sleep(20);
        exit(10);
    }
    else
    {
        //father
        int status;
        pid_t ret = wait(&status);
        if(ret < 0 )
        {
            perror("wait()\n");
        }
        else
        {
            if((status & 0X7F) == 0)
            {//正常退出
                printf("正常退出,child exit code:%d\n",(status>>8)&0XFF);
            else
            {
                printf("异常退出,sig code:%d\n",status & 0x7F);
            }
        }
    }
    return 0;
}                                
  • 运行结果:(20秒之后会输出下面的内容)

  • 如果在别的终端用信号来终止这个进程(如下利用9号信号来终止进程),运行结果如下:

四.进程等待的方式之waitpid
(1)waitpid函数的原型:
pid_t waitpid(pid_t pid, int* status, int options)
(2)返回值:
正常返回时,返回收集到的子进程的pid;当第三个参数设置为WNOHANG,当调用者发现没有没有已退出的子进程可收集(或者子进程还在运行),则返回0;如果调用出错,返回-1.
(3)参数:
①pid:
  • pid=-1,表示等待任意一个子进程;
  • pid>0表示等待指定的进程(其子进程的ID与pid相等的进程,由fork的返回值知道其子进程的pid)
②status:(与wait的参数status的用法一致)
还可以通过一些宏来获得:
  • WIFEXITED(status):若为真,表示进程正常退出(用于查看信号)
  • WEXITSTATUS(status):当WIFEXITED(status)为真时查看进程的退出码
③options:
  • 为0表示阻塞式等待,与wait的作用一致;
  • 为WNOHANG表示非阻塞等待
(4)测试代码:
①当waitpid的第三个参数为0时表示阻塞等待
#include<stdio.h>                                                                                                                                  
#include<unistd.h>
#include<wait.h>
#include<stdlib.h>

int main()
{
    pid_t pid = fork();
    if(pid == -1)
    {
        perror("fork()\n");
    }
    else if(pid == 0)
    {//child
     printf("child , pid = %d\n",getpid());
     sleep(5);
     exit(35);
    }
    else
    {//parent
        int status;
        pid_t ret = waitpid(-1,&status,0);  //阻塞式等待,-1表示等待任意一个进程
        if(ret == -1)
        {
            perror("wait()");
        }
        else
        {
            if(WIFEXITED(status))
            {//正常退出
                printf("正常退出,child exit code:%d\n",WEXITSTATUS(status));
            }
            else
            {
                printf("异常退出\n");
            }
        }
    }
    return 0;
}             
运行结果:

  • 当子进程被信号所终止时,运行结果如下:

非阻塞等待的测试代码
#include<stdio.h>                                                                                                                                                             
#include<stdlib.h>
#include<unistd.h>
#include<wait.h>
#include<stdlib.h>

int main()
{
    pid_t pid = fork();
    if(pid == -1)
    {
        perror("fork()");
    }
    else if(pid == 0)
    {//child
        printf("child, pid = %d\n",getpid());
        sleep(5);
        exit(60);
    }
    else
    {//parent
        int status;
        pid_t ret =0;
        do
        {
           ret =  waitpid(-1,&status,WNOHANG); //非阻塞式等待  
           if(ret == 0) //说明子进程还在运行
           {
               printf("child is running\n");
           }
           sleep(1);
        }while(ret == 0);

        //此时说明ret != 0
        if(WIFEXITED(status))
        {
            printf("child exit code:%d\n",WEXITSTATUS(status));
        }
   else
        {
            printf("sig code is %d\n",status & 0x7F);                                                                                                                         
        }
    }
    return 0;
}
运行结果:

  • 当子进程被信号所异常终止时,运行结果如下:



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值