linux系统编程-回收进程

孤儿进程和僵尸进程的概念

  • 孤儿进程:父进程先于子进程结束,则子进程成为孤儿进程,此时init进程变成子进程的父进程,称为init进程领养孤儿进程。
    在这里插入图片描述

  • 僵尸进程:进程终止,父进程尚未回收,子进程残留资源(PCB)存放于内核中,变成僵尸(Zombie)进程
    NOTE:僵尸进程不能使用kill命令清除,因为kill命令只是用来终止进程的,而僵尸进程已经终止。当父进程也死了,僵尸进程交给init进程解决了。
    在这里插入图片描述

wait函数

  • pid_t wait(int *status); 成功:清理掉的子进程ID;失败:-1 (无子进程)
    一次调用只回收一个子进程,回收多个子进程:while(wait(NULL));

  • 当进程终止时,操作系统的隐式回收机制会:
    (1) 关闭所有文件描述符
    (2) 释放用户空间分配的内存
    (3) 内核中PCB仍存在,其中保存该进程的退出状态。(正常终止→退出值;异常终止→终止信号)

  • 父进程调用wait函数可以回收子进程终止信息。该函数有三个功能:
    ① 阻塞等待子进程退出
    ② 回收子进程残留资源
    ③ 获取子进程结束状态(退出原因)。

  • 可使用wait函数传出参数status来保存进程的退出状态。借助宏函数来进一步判断进程终止的具体原因。宏函数可分为如下三组:
    (1)WIFEXITED(status) 为非0 → 进程正常结束
       WEXITSTATUS(status) 如上宏为真,使用此宏 → 获取进程退出状态 (exit的参数)
           child_pid = wait(&status);
           if(wpid>0)//子进程的PID应该 >0
           {
                 if(WIFEXITED(status))
                 {
                      printf("exit value is %d \n",WEXITSTATUS(status)); //子进程退出时的值x:exit(x) or return(x)
                 }
           }

(2)WIFSIGNALED(status) 为非0 → 进程异常终止
   WTERMSIG(status) 如上宏为真,使用此宏 → 取得使进程终止的那个信号的编号。

         wpid = wait(&status);
         if(wpid>0)
         {
                   if(WIFSIGNALED(status))
                   printf("signal value is %d \n",WTERMSIG(status));
         }

         如果子进程执行了 100/0的算术运算,父进程输出8,用kill -l 命令查看,则异常信号编号为8是SIGFPE,

(*3)WIFSTOPPED(status) 为非0 → 进程处于暂停状态( 拓展 )
    WSTOPSIG(status) 如上宏为真,使用此宏 → 取得使进程暂停的那个信号的编号。
   WIFCONTINUED(status) 为真 → 进程暂停后已经继续运行


waitpid函数

  • 作用同wait,但可指定pid进程清理,可以不阻塞
  • pid_t waitpid(pid_t pid, int *status, in options); 成功:返回清理掉的子进程ID;失败:-1( 无子进程)
    参数 pid:> 0 回收指定ID的子进程
          -1 回收任意子进程(相当于wait)
          0 回收和当前调用waitpid一个组的所有子进程
         < -1 回收指定进程组内的任意子进程
    参数options:为WNOHANG,且子进程正在运行。返回0
             :为0 ,且子进程正在运行。一直阻塞等待


例子1:父进程循环创建5个进程,只回收第3个进程
#include <stdio.h>
#include <stdlib.h>
 #include <unistd.h>
  
 int main(void)
{
         pid_t pid;
         int i=0,wpid;
        printf("------------------------\n");

       for(i=0;i<5;i++)
         {
         pid=fork();
                 if(pid<0)
                {
                         perror("fork error");
                 }
                 else if(pid == 0)
                {
                        break;
                 }
 
                 else
                 {
                         if(i==3)
                         wpid=pid;
                }
         }
         sleep(i);
         if(i<5)
         {
                 printf("i am %dth child,my pid is %d\n",i,getpid());
         }
         if(i==5)
         {
                 waitpid(wpid,NULL,0);
                 printf("i am father ,my pid is %d\n",getpid());
                 while(1);   //父进程停在这,
         }
 
         return 0;
 }

左边:执行结果                        右边:ps-aux 命令查看的进程
在这里插入图片描述




例子2:父进程回收全部进程


         if(i==5)
         {
                 while(waitpid(-1,NULL,0)>0); //循环回收,当没有子进程回收,返回-1,跳出
                 printf("i am father ,my pid is %d\n",getpid());
                 while(1);   //父进程停在这,
         } 

结果:只剩下父进程,子进程全部回收了,没有僵尸进程了
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/zzyczzyc/article/details/82943397