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状态。)