linux 之进程基础 (六)、进程API之进程资源回收函数

6. 进程API之进程资源回收函数

6.1 wait函数和waitpid函数 简介

6.1.1 wait函数

调用该函数使进程阻塞,直到任一个子进程结束或者是该进程接收到了一个信号为止。如果该进程没有子进程或者其子进程已经结束,wait函数会立即返回。

此时父进程属于可中断状态

6.1.2waitpid函数

功能和wait函数类似。可以指定等待某个子进程结束以及等待的方式(阻塞或非阻塞,由参数指定阻塞还是不阻塞.)。事实上wait()函数只是waitpid()函数的特例,内部实现wait()函数时,直接调用waitpid()。

6.2 wait函数

6.2.1 wait 函数原型

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

pid_t  wait(int  *status);

6.2.2 wait函数参数和返回值

6.2.2.1函数参数:
status是一个整型指针,指向的对象用来保存子进程退出时的状态。

  • A.status若为空
    表示忽略子进程退出时的状态 实际上回收了 但是不想看这个值是多少了
  • B.status若不为空

为什么需要一个status 指针 作为参数呢?
父进程要获取子进程的退出状态,需要在父进程中有一个位置来存储子进程的退出状态,因此需要在父进程中定义一个int型的指针变量传递给wait函数。

6.2.2.2 返回值

  • 成功
    返回已经回收的子进程的pid

  • 失败
    返回-1

6.3 waitpid函数

6.3.1 waitpid函数原型

#include <sys/types.h>
#include <sys/wait.h>
pid_t   waitpid(pid_t  pid,int *status,int options);

6.3.2 waitpid 函数参数

(1)参数为pid,有一下选项:

  • pid > 0:回收进程ID等于pid的子进程 即回收指定子进程
  • pid = -1:回收任何一个子进程,此时和wait作用一样
  • pid = 0 : 回收其组ID等于调用进程的组ID的任一子进程
  • 和调用进程 组id号(即:同一进程组)相同的任何一个id
  • pid < -1: 回收其组ID等于pid 绝对值的任一子进程 此时pid 填的是进程组id
    例如填 -7844 就可以回收7844 进程组中的任一进程

(2)status:

  • 同wait函数。

(3)options:

  • WNOHANG,若由pid指定的子进程并不立即可用,则waitpid不阻塞,此时返回值为0 假如需要等待的子进程属于睡眠状态,此时,父进程不等待子进程,而是立刻返回
  • WUNTRACED,若某实现作业控制操作,则由pid指定的任一子进程状态已暂停,且其状态自暂停以来还没报告过,则返回其状态。(一般不会用这个参数。)
  • 0:同wait,阻塞父进程,等待子进程退出。

6.3.3 waitpid函数返回值

  • 正常:结束的子进程的进程号
  • 使用选项WNOHANG且没有子进程结束时:0
  • 调用出错:-1

6.4 清除僵尸进程

6.4.1 如何清除僵尸? 三种方式

  • 父进程提前退出
  • 真父委托继父
  • 真父wait(真父回收)

6.4.2 三种方式介绍

  • 子进程在退出的过程中,内核会给其父进程发送一个信号,通知父进程来“收尸”。这个信号默认是SIGCHLD。如果父进程通过等待他(调用wait/ waitpid)回收了这个僵尸进程,那么内核就会立即释放掉task_struct,即僵尸很快就被清理了。
  • 父进程在创建子进程之前通知内核不想等待回收他,则内核在子进程结束后内核直接将子进程的僵尸回收掉。在Linux下 可以简单地将SIGCHLD信号的操作设为SIG_IGN。signal(SIGCHLD,SIG_IGN);通知涉及信号,在信号处理时再讲。
  • 如果子进程的父进程在子进程没有结束之前先结束了,那么该进程就不会变成僵尸进程,因为每个进程结束的时候,系统都会扫描当前系统中所运行的所有进程, 看有没有哪个进程是刚刚结束的这个进程的子进程,如果是的话,就由Init来接管他,成为他的父进程……。)而init成为子进程的继父进程后就会在其结束时负责清理它。
    注意:
    linux系统启动后,第一个被创建的用户态进程就是init进程。它有两项使命:
    1、执行系统初始化脚本,创建一系列的进程(它们都是init进程的子孙);
    2、在一个死循环中等待其子进程的退出事件,并调用waitid系统调用来完成“收尸”工作;init进程不会被暂停、也不会被杀死(这是由内核来保证的)。它在等待子进程退出的过程中处于TASK_INTERRUPTIBLE状态,“收尸”过程中则处于TASK_RUNNING状态。)
原文地址:https://www.cnblogs.com/lasnitch/p/12764128.html