wait和waitpid函数
一、孤儿进程和僵尸进程
孤儿进程:父进程先于子进程终止,子进程就沦为”孤儿进程“,会被init进程回收。
僵尸进程:子进程终止,尚未被父进程回收,则成为僵尸进程,无法用kill命令回收,这里要注意,每个进程结束后都必然会经历僵尸态,时间长短的差别而已。子进程终止时,子进程残留资源PCB存放于内核中,PCB记录了进程结束原因,进程回收就是回收PCB。回收僵尸进程,得kill它的父进程,让孤儿院init进程去回收它。
二、wait函数
wait函数: 回收子进程退出资源, 阻塞回收任意一个。
pid_t wait(int *status) status是传出参数
参数:(传出) 回收进程的状态。
返回值:成功: 回收进程的pid
失败: -1, errno
函数作用1: 阻塞等待子进程退出
函数作用2: 清理子进程残留在内核的 pcb 资源
函数作用3: 通过传出参数,得到子进程结束状态
获取子进程正常终止值:
WIFEXITED(status) --》 为真 --》调用 WEXITSTATUS(status) --》 得到 子进程 退出值。
获取导致子进程异常终止信号:
WIFSIGNALED(status) --》 为真 --》调用 WTERMSIG(status) --》 得到 导致子进程异常终止的信号编号。
一个进程终止时会关闭所有文件描述符,释放在用户空间分配的内存,但它的PCB还保留着,内核在其中保存了一些信息:如果是正常终止则保存着退出状态,如果是异常终止则保存着导致该进程终止的信号是哪个。这个进程的父进程可以调用wait或者waitpid获取这些信息,然后彻底清除掉这个进程。我们知道一个进程的退出状态可以在shell中用特殊变量$?查看,因为shell是它的父进程,当它终止时,shell调用wait或者waitpid得到它的退出状态,同时彻底清除掉这个进程。
三、waitpid函数
waitpid函数: 指定某一个进程进行回收。可以设置非阻塞。
waitpid(-1, &status, 0) == wait(&status);
pid_t waitpid(pid_t pid, int *status, int options)
参数:
pid:指定回收某一个子进程pid
> 0: 待回收的子进程pid
-1:任意子进程
0:同组的子进程。
status:(传出) 回收进程的状态。
options:WNOHANG 指定回收方式为,非阻塞。
返回值:
> 0 : 表成功回收的子进程 pid
0 : 函数调用时, 参3 指定了WNOHANG, 并且,没有子进程结束。
-1: 失败。errno
一次wait/waitpid函数调用,只能回收一个子进程。上一个例子,父进程产生了5个子进程,wait会随机回收一个,捡到哪个算哪个。
使用waitpid回收指定子进程演示,几个注意的点:
1、循环创建子进程时,利用break使得子进程不进入fock
2、子进程中获取子进程pid,getpid;父进程中获取子进程pid直接利用fork函数的返回值即可
3、回收指定的子进程有两种方式,
用阻塞的方式回收,waitpid(tpid,NULL,0);缺点命令符会和输出混在一起
用非阻塞加延时的方式回收,waitpid(tpid,NULL,WNOHANG);如果不使用延时sleep,可能返回值为0,因为要回收的子进程还没有结束
4、循环回收多个子进程
一般采用非阻塞加上延迟的方式
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 终于写完轮子一部分:tcp代理 了,记录一下
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理