父进程等待子进程结束 waitpid wait
我们一直在强调一个概念就是进程是一个程序执行的实例,是内核在虚拟概念下创建的实体,它实例化的体现在用户态就是程序代码和代码使用的变量(存储空间),在内核态就是内核为我们每个进程所保存的数据结构(状态信息)等。
当一个进程由于某种原因停止时,内核并不是直接将为它保存的状态信息从内核移除,相反,进程会一直被保持在一种已经终止的状态,直到被它的父进程回收,当父进程回收已经终止的子进程时,内核会将子进程的退出状态传递给父进程,然后抛弃已经终止的进程,从此刻开始,这个进程才会消失,一个子进程结束但是还没有被父进程回收的进程叫做”僵尸进程”,要是父进程先于子进程结束,那么它的子进程就会称为”孤儿进程”,最终会被PID为1的init进程收养。什么?init进程?好眼熟,对,它是我们引入进程的概念时候提过的。下面我们将介绍父进程等待子进程结束的两个函数,wait()和waitpid()函数。
首先我们来看下man wait的内容:
#include <sys/types.h>
#include <sys/wait.h>
pid_t wait(int *status); //status表示退出状态,指向子进程的退出码
返回:如果成功,返回子进程的ID;如果失败,返回-1。
pid_t waitpid(pid_t pid, int *status, int options); //option可选择设置waitpid不堵塞
返回:如果成功,返回子进程的ID;如果option设置为WNOHANG,则为0;如果其他错误,则为-1。
waitpid()函数:
默认的,当option参数为0的时候,它挂起等待一个子进程的结束;如果子进程中一个进程在刚调用的时候就已经结束了,那么waitpid()就会立即返回,如果正常情况下,这两种都会返回已经终止的进程的PID,并且将这个进程从系统中去除。下面我们再来详细介绍下它的三个参数:
(1):pid:判定等待集合的成员
pid > 0 : 表示等待集合中进程号为pid的特定子进程。
pid = -1 : 表示等待进程的任意一个子进程。
pid = 0 : 表示等待其组ID等于调用进程的组ID的任意一个进程。
(2):status:检查已回收的子进程的退出状态,主要是利用wait.h头文件中的几个宏来检测。
WIFEXITED(status) : 如果子进程通过调用exit或者return正常终止,那么就返回真。
WEXITSTATUS(status) : 返回一个正常终止的子进程的退出状态,返回子进程中exit或_exit的低八位。
WIFSIGNALED(status) : 若子进程异常终止,它就取得一个非零值,表示真。
(3):options : 修改默认行为,介绍最常用的一个。
WNOHANG : 如果等待集合中的任意一个子进程都还没有终止,那么就立即返回,(返回值为0),默认的行为是挂起调用进程等待,直到有子进程结束,这样可以避免阻塞,我们还可以在等待子进程结束的同时干点别的什么事。
下面我们来看一段代码:
#include<stdio.h>
#include<sys/types.h>
#include<sys/wait.h>
#include<errno.h>
#include<unistd.h>
#include<stdlib.h>
int main(int argc,char *argv[])
{
pid_t pid;
int status;
printf("Hello\n");
pid = fork();
if(pid != 0) {
if(waitpid(-1,&status,0) > 0) {
if(WIFEXITED(status) != 0) {
printf("%d\n",WEXITSTATUS(status));
}
}
}
printf("Bye\n");
exit(100);
}
输出为什么是4行大家懂不懂呢,首先输出Hello没有什么解释的,然后在fork之后我们可以看做有两份一样的代码分别属于父进程和子进程,然后子进程输出Bye,此时的父进程已经被挂起等待子进程的结束,然后子进程100退出码退出,此时父进程结束挂起状态,WEXITSTATUS(status)输出退出码,接着向下执行,再次输出Bye!
错误条件:如果调用进程没有子进程,那么waitpid()函数返回-1,并且设置errno的值为ECHILD;如果waitpid()函数被一个信号中断,那么返回-1,并且设置errno的值为EINTR。举个例子:
#include<stdio.h>
#include<sys/types.h>
#include<sys/wait.h>
#include<errno.h>
int main(int argc,char *argv[])
{
pid_t pid;
int status;
pid = waitpid(-1,&status,0);
printf("pid is %d\n",pid);
if(errno == ECHILD) {
perror("waitpid");
}
}
我们可以看到对于没有子进程的进程如果调用waitpid()函数的话返回-1,并且将errno值设置为ECHILD,我们可以用perror()函数打印出来错误原因是没有子进程。
wait()函数
介绍完waitpid()函数,wait()函数实际上就不用多说了,它是waitpid()函数的简单版本
wait(status) = waitpid(-1,&status,0)。来段代码练练手:
#include<stdio.h>
#include<sys/wait.h>
#include<sys/types.h>
#include<unistd.h>
#include<stdlib.h>
int main(int argc,char *argv[])
{
int pid;
char *msg;
int k;
int exit_code;
pid = fork();
switch(pid){
case 0:{
printf("curpid = %d,parentpid = %d\n",pid,getppid());
msg = "children process is running";
k = 5;
exit_code = 55;
break;
}
case -1:{
perror("process creat failed\n");
exit(-1);
}
default:{
printf("childpid is %d ,parentpid is %d\n",pid,getpid());
exit_code = 0;
break;
}
}
printf("------------------------%d\n",pid);
if(pid != 0)
{
int stat_val; // 值为0
int child_pid;
child_pid = wait(&stat_val); //wait函数的返回值是终止运行的子进程的pid, 遇到wait函数之后开始执行子进程.
printf("child process has exited,pid = %d\n",child_pid);
if(WIFEXITED(stat_val)){
printf("child exited with code %d\n",WEXITSTATUS(stat_val));
}
else {
printf("child exited abnormally\n");
}
}
//让子进程暂停5秒
else
{
while(k-- > 0)
{
puts(msg);
sleep(1);
}
}
exit(exit_code);
}
我们首先fork一个子进程,然后子进程执行的是case 0 中的代码以及下面else中的代码,父进程执行default中代码和下面if中的代码,但是父进程到wait函数的时候就会挂起来等待子进程的结束。子进程连续输出5次msg的内容之后退出,exit_code=55;这个会被父进程中的 WEXITSTATUS(stat_val) 检测到。
版权声明:本文为博主原创文章,未经博主允许不得转载。
父进程等待子进程结束 waitpid wait的更多相关文章
- Linux下利用fork()创建子进程并使父进程等待子进程结束
int status; pid_t t = fork(); if(t){ waitpid(t, &status, 0); }else{ system("vi temp ...
- fork新建进程——父进程等待子进程结束
#include <sys/types.h>#include<sys/wait.h>#include<unistd.h>#include<stdio.h> ...
- linux 进程等待 wait 、 waitpid
waitpid() 与 wait() 功能相似,都是用户主进程等待子进程结束或中断. 可用于进程之间的同步 wait 函数原型 pid_t wait(int *status); 函数说明 wait() ...
- linux系统编程之进程(六):父进程查询子进程的退出,wait,waitpid
本节目标: 僵进程 SIGCHLD wait waitpid 一,僵尸进程 当一个子进程先于父进程结束运行时,它与其父进程之间的关联还会保持到父进程也正常地结束运行,或者父进程调用了wait才告终止. ...
- linux 进程学习笔记-等待子进程结束
<!--[if !supportLists]-->Ÿ <!--[endif]-->等待子进程结束 pid_t waitpid(pid_t pid, int *stat_loc, ...
- Linux 进程--父进程查询子进程的退出状态
僵尸进程 当一个子进程先于父进程结束运行时,它与其父进程之间的关联还会保持到父进程也正常地结束运行,或者父进程调用了wait才告终止. 子进程退出时,内核将子进程置为僵尸状态,这个进程称为僵尸进程,它 ...
- PHP多进程学习(三)__代码案例来了解父进程与子进程的执行顺序
pcntl_fork创建子进程成功的话,系统就有了2个进程,一个为父进程,一个为子进程,父进程和子进程都继续向下执行,子进程的id号为$pid(父进程会获取子进程的$pid也就是$pid不为0,而子进 ...
- 【LINUX】主进程、父进程、子进程、守护进程的概念
一.摘要 详解父进程.子进程.守护进程的区别,例子稍候补充 二.定义区别 主进程 程序执行的入口,可以理解为常用的main 函数 父进程 对于子进程而言, 子进程的创造者,可有多个子进程. 任何进程都 ...
- swoole父进程和子进程之间通信的例子
<?php /** 这是一个swoole父进程和子进程之间通信的例子 */ //进程创建成功后回调处理 function handle(swoole_process $worker){ //从进 ...
随机推荐
- 自定义滚动条 - mCustomScrollbar
项目中需要使用自定义滚动条,但是试用了很多都功能不够全,今天发现一个比较全而且用法很简单的 -- mCustomScrollbar http://manos.malihu.gr/jquery-cust ...
- JavaScript中的arguments,callee,caller
在提到上述的概念之前,首先想说说javascript中函数的隐含参数: arguments: arguments 该对象代表正在执行的函数和调用它的函数的参数. [function.]argument ...
- Linux常用的安全工具 转自https://yq.aliyun.com/articles/52540?spm=5176.100239.blogcont24250.8.CfBYE9
摘要: 原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 .作者信息和本声明.否则将追究法律责任.http://chenguang.blog.51cto.com/350944/85790 ...
- virtualbox 使用USB引导启动安装系统
想要测试u盘系统引导有没有问题,从u盘中启动我烧录的Android x86系统. 这种方式可以在已有空的虚拟机上直接启动U盘中的系统. 百度上能搜到的方式都是使用CMD命令(懒人表示太麻烦--),so ...
- MS SQL执行大脚本文件时,提示“内存不足”的解决办法()
问题描述: 当客户服务器不允许直接备份时,往往通过导出数据库脚本的方式来部署-还原数据库, 但是当数据库导出脚本很大,用Microsoft SQL Server Management Studio执行 ...
- table中bordercolor属性设置后最新ie浏览器或firefox中不显示边线,借助table的css来实现边线
table中的bordercolor属性设置后在最新的ie或者firefox中均不显示边线,table的边线又是常用功能.只能使用css来实现了,更通用,更方便一些. css: .ctable{ b ...
- knockout+bootstrap--一些复杂的应用合集
一.针对My97日历控件的绑定 普通绑定和特殊格式绑定(红色部分) <!-- ko foreach: items --> <td class="ruyeeTableTDLa ...
- 浅谈mybatis中的#和$的区别
1. #将传入的数据都当成一个字符串,会对自动传入的数据加一个双引号.如:order by #user_id#,如果传入的值是111,那么解析成sql时的值为order by "111&qu ...
- sublime text2在windows中以命令行启动
sublime text2在windows中以命令行启动 把执行文件添加到PATH中即可,如图: 如果你和我一样习惯了mac下的简写subl,那么需要在程序目录中新建一个批处理文件subl.bat ...
- 原生js+本地储存登录注册
//简易操作,只能当前页面储存一个username和password. <!DOCTYPE html> <html> <head> <meta charset ...