进程调用 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. iOS 数据安全、数据加密传输

    近期接到一个新需求:APP企业版需要接入热更新功能. 热更新需要下发补丁脚本, 脚本下发过程中需要保证脚本传输安全,且需要避免中间人攻击. 需要用到数据加密传输方面的知识,以下是我设计的加密解密流程: ...

  2. Python 基础 类的继承

    如果寂静定义了Person类,需要定义新的Student 和Teacher 类时 可以直接从Person 中继承 class Person(Object): def __init__(self,nam ...

  3. Mysql 简单的使用定时器调用存储过程

    1.创建测试的表 CREATE TABLE mytable (    id INT auto_increment NOT NULL,    NAME VARCHAR (100) NOT NULL DE ...

  4. [Linux]使用宝塔面板做负载均衡时遇到的问题和解决办法

    最近公司的小程序因为高峰期访问缓慢的问题,打算用负载均衡试试.本人是个新手,在网上找了几篇负载均衡的文章看了看,最后还是用了宝塔面板的负载均衡插件...这个服务器我也是刚刚接手,很多东西都是以前的同事 ...

  5. Linux 判断系统任务是否正在运行

    #!/bin/bash if ps -ef|grep "php index"|egrep -v grep >/dev/null then >& >> ...

  6. Python enumerate()方法

    for循环中如果要获取当前元素的索引值,一个方法是定义一个计数器,每次取值的时候将这个值加一,如果是列表的话可以用index()函数,而python中有一个比较简洁的方法而已直接获得索引值,并可以方便 ...

  7. 使用maven将GitHub上项目打包作为依赖添加

    Clone GitHub项目 git clone https://github.com/LeeKemp/UserAgentParser 将项目打成jar包,安装到maven仓库中 D:\Github ...

  8. centos系统误删libc.so.6

    前段时间遇到开发人员更新glibc版本,把/usr/lib64/libc-2.12.so & libc.so.6 -> libc-2.12.so 这个软连接更改之后导致报错: ls: e ...

  9. dart 自己写一个简单的文件编码器

    // import 'dart:convert'; import 'dart:io'; main() async { var src = File('./lib/convert/source.txt' ...

  10. Matlab调用C语言函数

    Matlab调用C语言函数 如果我有一个用C语言写的函数,实现了一个功能,如一个简单的函数:double add(double x, double y) { return x + y ;}现在我想要在 ...