进程调用 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的更多相关文章

  1. Linux内核学习笔记-2.进程管理

    原创文章,转载请注明:Linux内核学习笔记-2.进程管理) By Lucio.Yang 部分内容来自:Linux Kernel Development(Third Edition),Robert L ...

  2. Linux内核学习笔记-1.简介和入门

    原创文章,转载请注明:Linux内核学习笔记-1.简介和入门 By Lucio.Yang 部分内容来自:Linux Kernel Development(Third Edition),Robert L ...

  3. Linux内核学习笔记二——进程

    Linux内核学习笔记二——进程   一 进程与线程 进程就是处于执行期的程序,包含了独立地址空间,多个执行线程等资源. 线程是进程中活动的对象,每个线程都拥有独立的程序计数器.进程栈和一组进程寄存器 ...

  4. 20135316王剑桥Linux内核学习笔记

    王剑桥Linux内核学习笔记 <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 计算机是如何工作的 个人理 ...

  5. 深入理解Linux内核 学习笔记(3)

    第三章 进程 可以看到很多熟悉的结构体 进程状态: 可运行状态(TASK_ RUNNING) 进程要么在CPU上执行,要么准备执行. 可巾断的等待状态(TASK_ INTERRUPTIBLE) 进程被 ...

  6. Linux内核学习笔记之seq_file接口创建可读写proc文件

    转自:http://blog.csdn.net/mumufan05/article/details/45803219 学习笔记与个人理解,如有错误,欢迎指正. 温馨提示:建议跟着注释中的编号顺序阅读代 ...

  7. Linux内核学习笔记

    1.vanbreaker的专栏 2.LinuxKernel Exploration 3.DroidPhone的专栏 4.Linux内核研究以及学习文档和ARM学习以及研究的开放文档   [力荐] 5. ...

  8. 20135316王剑桥Linux内核学习笔记第四周

    20135316王剑桥 <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC 1000029000 1.内核态:在高执行级别,代码可 ...

  9. Linux内核学习笔记——内核内存管理方式

    一 页 内核把物理页作为内存管理的基本单位:内存管理单元(MMU)把虚拟地址转换为物理 地址,通常以页为单位进行处理.MMU以页大小为单位来管理系统中的也表. 32位系统:页大小4KB 64位系统:页 ...

随机推荐

  1. Bridge(桥接)模式

    1. 概述 在软件系统中,某些类型由于自身的逻辑,它具有两个或多个维度的变化,那么如何应对这种“多维度的变化”?如何利用面向对象的技术来使得该类型能够轻松的沿着多个方向进行变化,而又不引入额外的复杂度 ...

  2. ./redis-trib.rb 报错:/usr/local/rvm/gems/ruby-2.4.2/gems/redis-4.0.1/lib/redis/client.rb:119:in `call': ERR Slot 0 is already busy (Redis::CommandError)

    错误提示是 slot插槽被占用了(这是 搭建集群前时,以前redis的旧数据和配置信息没有清理干净.) 解决方案是 用redis-cli 登录到每个节点执行  flushall  和 cluster ...

  3. 【css】 如何修改select的样式

    select { /*清除select默认样式*/ appearance:none; -moz-appearance:none; -webkit-appearance:none; -ms-appear ...

  4. 再论C++引用(reference)类型

    很多C++初学者搞不清楚C++引用类型,不知有什么用,所以也不知怎么用.一个问题令人迷惑,不是读者有问题,而是教科书有问题. 和多数初学者一样,笔者在初学C++时,关于引用类型,教科书上也是如下表所述 ...

  5. 这次的PION的总结

    这次的PION的总结 果然不出所料,才\(129\)分. 同级的巨佬们\(170,180,\color {red}{280}\)\(\small{wc这什么神仙啊QAQ}\),都比我强 那我还有什么可 ...

  6. 【Linux】文件、目录权限及归属

    访问权限: 可读(read):允许查看文件内容.显示目录列表 可写(write):允许修改文件内容,允许在目录中新建.移动.删除文件或子目录 可执行(execute):允许运行程序.切换目录 归属: ...

  7. VB错误说明

    1001 800A03E9 内存不足 1002 800A03EA 语法错误 1003 800A03EB 缺少“:” 1005 800A03ED 需要 '(' 1006 800A03EE 需要 ')' ...

  8. JavaScript入门学习(0)相关 软件工具

    JavaScript本地脚本编辑工具(1st JavaScript Editor Pro ) 必要设置     https://pan.baidu.com/s/1XoaNA9o0qt2eJfLgoZ5 ...

  9. 初识HDFS原理及框架

    目录 HDFS是什么 HDFS的优缺点 HDFS的框架 HDFS的读写流程 HDFS命令 HDFS参数 1. HDFS是什么 HDFS(Hadoop Distributed File System)是 ...

  10. hive 优化 (转)

    Hive优化 Hive优化目标 在有限的资源下,执行效率更高 常见问题 数据倾斜 map数设置 reduce数设置 其他 Hive执行 HQL --> Job --> Map/Reduce ...