Linux内核学习笔记(4)-- wait、waitpid、wait3 和 wait4
进程调用 exit() 退出执行后,被设置为僵死状态,这时父进程可以通过 wait4() 系统调用查询子进程是否终结,之后再进行最后的操作,彻底删除进程所占用的内存资源。 wait4() 系统调用由 linux 内核实现,linux 系统通常提供了 wait()、waitpid()、wait3()、wait4() 这四个函数,四个函数的参数不同,语义也有细微的差别,但是都返回关于终止进程的状态信息。
1、wait() 函数:
wait() 函数的原型是:
#include <sys/types.h> // 提供类型 pid_t 的定义
#include <sys/wait.h> pid_t wait(int *status);
当进程调用 wait() 时,会暂停目前进程的执行(即阻塞),由 wait() 来自动分析是否当前进程的某个子进程已经退出,如果找到了这样一个已经变成僵尸进程的子进程,wait 就会收集这个子进程的信息,并将其彻底销毁后返回;如果没有找到这样一个子进程,wait 就会一直阻塞在这里,直到出现僵尸进程。
参数 status 保存着子进程退出时的一些状态(包括 task_struct、thread_info及内核栈等)它是一个指向 int 类型的指针;如果不在意子进程的结束状态值,只想把这个僵尸进程消灭掉(实际上,大多数时候都是这样做的),则可以将这个参数设为 NULL,即:
pid = wait(NULL); // 不管子进程的结束状态,直接杀死进程
如果 wait() 调用成功,则会返回被收集子进程的进程ID;如果被调用进程没有子进程,则调用失败,返回 -1
接下来用一段代码来演示一下 wait() 的用法:
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h> void main(){
pid_t fpid,rpid;
fpid = fork();
if(fpid < ){
perror("error on forking!\n");
}
else if(fpid == ){
printf("this is a child process! the pid is %d\n",getpid());
sleep();
}
else{
rpid = wait(NULL); // 如果 wait()调用成功,则返回子进程的PID;如果调用失败,则返回 -1
printf("Catch the child process with pid of %d\n",rpid);
}
exit();
}
输出结果如下:

关于 status 参数,比较复杂,暂时不做讨论,可以参考这里:https://www.ibm.com/developerworks/cn/linux/kernel/syscall/part3/index.html
2、waitpid() 函数:
函数原型:
#include <sys/types.h>
#include <sys/wait.h> pid_t waitpid(pid_t pid,int *status,int options);
waitpid() 函数的功能与 wait() 的功能类似,不过,它比 wait() 函数多了两个参数:
1)参数 pid 为欲等待的子进程的识别码:
pid < -1 ;等待进程组 ID 为 pid 绝对值的进程组中的任何子进程;
pid = -1 ;等待任何子进程,此时 waitpid() 相当于 wait()。实际上,wait()就是 pid = -1、options = 0 的waitpid(), 且有:
static inline pid_t wait(*status){
return waitpid(-,*status,);
}
pid = 0 ;等待进程组 ID 与当前进程相同的任何子进程(也就是等待同一个进程组中的任何子进程);
pid > 0 ;等待任何子进程 ID 为 pid 的子进程,只要指定的子进程还没有结束,waitpid() 就会一直等下去。
2)参数 options 提供一些额外的选项来控制 waitpid():
WNOHANG;如果没有任何已经结束了的子进程,则马上返回,不等待;
WUNTRACED;如果子进程进入暂停执行的情况,则马上返回,但结束状态不予理会;
也可以将这两个选项组合起来使用,使用 OR 操作。如果不想使用这两个选项,也可以直接把 options 设为0 ,如下:
waitpid(-,NULL,WNOHANG | WUNTRACED); // 没有任何已结束了的子进程或子进程进入暂停执行的状态,则马上返回不等待
waitpid(-,NULL,); // options 设为0,则 waitpid() 会一直等待,直到有进程退出
3)waitpid() 的返回值,有三种:
a)正常返回时,waitpid() 返回收集到的子进程的PID;
b)如果设置了 WNOHANG,而调用 waitpid() 时,没有发现已退出的子进程可收集,则返回0;
c)如果调用出错,则返回 -1,这时erron 会被设置为相应的值以指示错误所在。(当 pid 所指示的子进程不错在,或此进程存在,但不是调用进程的子进程, waitpid() 就会返回出错,这时 erron 被设置为 ECHILD)
1 #include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h> void main(){
pid_t fpid,rpid; // fpid为fork()的返回值,rpid为waitpid()的返回值
fpid = fork();
if(fpid < ){
printf("error on forking");
}
else if(fpid == ){ // 子进程中 fork() 返回值为0
printf("this is a child process,pid is %d\n",getpid());
sleep(); // 睡眠10s,10s 后子进程退出
exit();
}
do{ // 父进程中,fork()返回新创建子进程的 PID
rpid = waitpid(fpid,NULL,WNOHANG); // 等待 PID = fpid 的进程(即子进程)退出,设置了WNOHANG选项,表明当没有发现已退出的子进程时不用等待直接返回,返回值为0;
if(rpid == ){ // rpid = 0,说明没有发现已退出的子进程
printf("No child exited\n");
sleep();
}
}while(rpid == );
if(fpid == rpid) // 成功收集了退出的子进程,返回值为被收集子进程的PID
printf("successfully get child process %d\n",rpid);
else
printf("error!\n");
}
结果如下:

从结果中可以看到,在子进程休眠的10s时间里,waitpid() 并没有一直等待,而是直接返回0,然后做自己的事情(睡眠1s),如此重复了10次;当子进程退出时,waitpid() 收集到退出的子进程,并返回所收集子进程的PID。
3、wait3()、wait4() 函数:
函数原型:
#include <sys/tpyes.h>
#include <sys/wait.h> pid_t wait3(int *status,int options,struct rusage *rusage);
pid_t wait4(pid_t pid,int *status,int options,struct rusage *rusage);
wait3() 和 wait4() 函数除了可以获得子进程状态信息外,还可以获得子进程的资源使用信息,这些信息是通过参数 rusage 得到的。而 wait3() 与 wait4() 之间的区别是,wait3() 等待所有进程,而 wait4() 可以根据 pid 的值选择要等待的子进程,参数 pid 的意义与 waitpid() 函数的一样。
本文主要参考:
https://www.ibm.com/developerworks/cn/linux/kernel/syscall/part3/index.html
Linux内核学习笔记(4)-- wait、waitpid、wait3 和 wait4的更多相关文章
- Linux内核学习笔记-2.进程管理
原创文章,转载请注明:Linux内核学习笔记-2.进程管理) By Lucio.Yang 部分内容来自:Linux Kernel Development(Third Edition),Robert L ...
- Linux内核学习笔记-1.简介和入门
原创文章,转载请注明:Linux内核学习笔记-1.简介和入门 By Lucio.Yang 部分内容来自:Linux Kernel Development(Third Edition),Robert L ...
- Linux内核学习笔记二——进程
Linux内核学习笔记二——进程 一 进程与线程 进程就是处于执行期的程序,包含了独立地址空间,多个执行线程等资源. 线程是进程中活动的对象,每个线程都拥有独立的程序计数器.进程栈和一组进程寄存器 ...
- 20135316王剑桥Linux内核学习笔记
王剑桥Linux内核学习笔记 <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 计算机是如何工作的 个人理 ...
- 深入理解Linux内核 学习笔记(3)
第三章 进程 可以看到很多熟悉的结构体 进程状态: 可运行状态(TASK_ RUNNING) 进程要么在CPU上执行,要么准备执行. 可巾断的等待状态(TASK_ INTERRUPTIBLE) 进程被 ...
- Linux内核学习笔记之seq_file接口创建可读写proc文件
转自:http://blog.csdn.net/mumufan05/article/details/45803219 学习笔记与个人理解,如有错误,欢迎指正. 温馨提示:建议跟着注释中的编号顺序阅读代 ...
- Linux内核学习笔记
1.vanbreaker的专栏 2.LinuxKernel Exploration 3.DroidPhone的专栏 4.Linux内核研究以及学习文档和ARM学习以及研究的开放文档 [力荐] 5. ...
- 20135316王剑桥Linux内核学习笔记第四周
20135316王剑桥 <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC 1000029000 1.内核态:在高执行级别,代码可 ...
- Linux内核学习笔记——内核内存管理方式
一 页 内核把物理页作为内存管理的基本单位:内存管理单元(MMU)把虚拟地址转换为物理 地址,通常以页为单位进行处理.MMU以页大小为单位来管理系统中的也表. 32位系统:页大小4KB 64位系统:页 ...
随机推荐
- HDFS的Read过程分析
在hadoop中作为后端存储的文件系统HDFS发挥中重要的作用,HDFS是一个分布式文件系统,按照Google File System的思想开发的,针对的场景是低端服务器.写操作少而读操作多的情况.在 ...
- Knowledge Point 20180506 深究Java的跨平台特性
本章主题:从骨子里看Java的跨平台;本文内容部分摘自https://www.cnblogs.com/roger-yu/p/5827452.html 有过基础Java知识的开发人员都知道Java是跨平 ...
- 关于修改计算机名称导致无法启动Oracle监听?
解决方法: 修改D:\app\‘admin’\product\11.2.0\dbhome_1\NETWORK\ADMIN\路径下的listener.ora和tnsnames.ora文件配置中的host ...
- DBA手记-BBED 的说明
在10g中连接生成bbed:cd $ORACLE_HOME/rdbms/libmake -f ins_rdbms.mk $ORACLE_HOME/rdbms/lib/bbed 11g中缺省未提供BBE ...
- 转:SQLServer中的GROUPING,ROLLUP和CUBE
转自:https://www.cnblogs.com/nikyxxx/archive/2012/11/27/2791001.html 聚集函数:GROUPING 用于汇总数据用的运算符: ROLLUP ...
- 1004. Counting Leaves(30)—PAT 甲级
A family hierarchy is usually presented by a pedigree tree. Your job is to count those family member ...
- 【PTA 天梯赛】L3-003 社交集群(并查集)
当你在社交网络平台注册时,一般总是被要求填写你的个人兴趣爱好,以便找到具有相同兴趣爱好的潜在的朋友.一个“社交集群”是指部分兴趣爱好相同的人的集合.你需要找出所有的社交集群. 输入格式: 输入在第一行 ...
- 升级Xcode10报错问题修复
Xcode10 问题1 报文件重复 File--> Workspace Settings --> Build System 修改为Legacy Build System (默认是New B ...
- Phaser3 对象池随机产生炸弹并销毁
效果图 对象池 Object Pool scene.js /// <reference path="../../libs/phaser/phaser.min.js"/> ...
- java通过get或post方式传到PHP的某控制器的某方法下
[java]package test4;import java.io.BufferedReader;import java.io.IOException;import java.io.InputStr ...