wait/waitpid函数与僵尸进程、fork 2 times
一、僵尸进程
当子进程退出的时候,内核会向父进程发送SIGCHLD信号,子进程的退出是个异步事件(子进程可以在父进程运行的任何时刻终止)
子进程退出时,内核将子进程置为僵尸状态,这个进程称为僵尸进程,它只保留最小的一些内核数据结构,以便父进程查询子进程的退出状态。
父进程查询子进程的退出状态可以用wait/waitpid函数。
二、如何避免僵尸进程
当一个子进程结束运行时,它与其父进程之间的关联还会保持到父进程也正常地结束运行或者父进程调用了wait/waitpid才告终止。
进程表中代表子进程的数据项是不会立刻释放的,虽然不再活跃了,可子进程还停留在系统里,因为它的退出码还需要保存起来以备父进程中后续的wait/waitpid调用使用。它将称为一个“僵进程”。
调用wait或者waitpid函数查询子进程退出状态,此方法父进程会被挂起(waitpid可以设置不挂起)。
如果不想让父进程挂起,可以在父进程中加入一条语句:signal(SIGCHLD,SIG_IGN);表示父进程忽略SIGCHLD信号,该信号是子进程退出的时候向父进程发送的。也可以不忽略SIGCHLD信号,而接收在信号处理函数中调用wait/waitpid。
// 让子进程退出后自动回收,避免成为僵尸或者需要父进程 wait。
struct sigaction sat_cld = { .sa_handler = SIG_IGN, .sa_flags = SA_NOCLDWAIT };
sigaction(SIGCHLD, &sat_cld, NULL);
而在运维中常用的手段是杀死父进程,这样子进程会由init 进程接管,由它来清理子进程的状态。
三、wait函数
头文件<sys/types.h>和<sys/wait.h>
函数功能:当我们用fork启动一个进程时,子进程就有了自己的生命,并将独立地运行。有时,我们需要知道某个子进程是否已经结束了,我们可以通过wait安排父进程在子进程结束之后。
函数原型
pid_t wait(int *status)
函数参数
status:该参数可以获得你等待子进程的信息
返回值:
成功等待子进程, 函数返回等待子进程的ID
wait系统调用会使父进程暂停执行,直到它的一个子进程结束为止。
返回的是子进程的PID,它通常是结束的子进程
状态信息允许父进程判定子进程的退出状态,即从子进程的main函数返回的值或子进程中exit语句的退出码。
如果status不是一个空指针,状态信息将被写入它指向的位置
通过以下的宏定义可以获得子进程的退出状态
WIFEXITED(status)
如果子进程正常结束,返回一个非零值
WEXITSTATUS(status) 如果WIFEXITED非零,返回子进程退出码
WIFSIGNALED(status) 子进程因为捕获信号而终止,返回非零值
WTERMSIG(status) 如果WIFSIGNALED非零,返回信号代码
WIFSTOPPED(status) 如果子进程被暂停,返回一个非零值
WSTOPSIG(status) 如果WIFSTOPPED非零,返回一个信号代码
四、waitpid函数
函数功能:用来等待某个特定进程的结束
函数原型:
pid_t waitpid(pid_t pid, int *status,int options)
参数:
status:如果不是空,会把状态信息写到它指向的位置
options:允许改变waitpid的行为,最有用的一个选项是WNOHANG,它的作用是防止waitpid把调用者的执行挂起等待(return immediately if no child has exited.)
返回值:如果成功, 返回等待子进程的ID,失败返回-1
对于waitpid的p i d参数的解释与其值有关:
pid == -1 等待任一子进程。于是在这一功能方面waitpid与wait等效。
pid > 0 等待其进程I D与p i d相等的子进程。
pid == 0 等待其组I D等于调用进程的组I D的任一子进程。换句话说是与调用者进程同在一个组的进程。
pid < -1 等待其组I D等于p i d的绝对值的任一子进程。
五、wait和waitpid函数的区别
两个函数都用于等待进程的状态变化,包括正常退出,被信号异常终止,被信号暂停,被信号唤醒继续执行等。
在一个子进程终止前, wait 使其调用者阻塞,而waitpid 有一选择项,可使调用者不阻塞。
waitpid并不只能等待第一个终止的子进程—它有若干个选择项,可以控制它所等待的特定进程。
实际上wait函数是waitpid函数的一个特例。
RETURN VALUE
wait(): on success, returns the process ID of the terminated child; on error, -1 is returned.
waitpid(): on success, returns the process ID of the child whose
state has changed; if WNOHANG was specified and one or more
child(ren) specified by pid exist, but have not yet changed state, then 0 is returned. On error, -1 is returned.
示例程序:
|
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 |
/*************************************************************************
> File Name: process_.c > Author: Simba > Mail: dameng34@163.com > Created Time: Sat 23 Feb 2013 02:34:02 PM CST ************************************************************************/ #include<sys/types.h> #include<sys/stat.h> #include<unistd.h> #include<fcntl.h> #include<stdio.h> #include<stdlib.h> #include<errno.h> #include<string.h> #include<sys/wait.h> #define ERR_EXIT(m) \ int main(int argc, char *argv[]) if (pid == 0) printf("this is parent\n"); return 0; |
输出为:
simba@ubuntu:~/Documents/code/linux_programming/APUE/process$ ./wait
this is parent
this is child
ret=7156, pid=7156
child exited abnormal signal number=6
说明子进程被信号异常终止,因为我们调用了abort(), 即产生SIGABRT信号将子进程终止,可以查到此信号序号为6。如果我们不使用abort 而是exit(100), 则应该输出 child exited normal exit status=100 ,即正常退出。
也就是所谓两次 fork 调用,主进程并不直接创建目标子进程,而是通过创建一个 Son,然后再由Son 创建实际的目标子进程 Grandson。Son 在创建
Grandson 后立即返回,并由主进程 waitpid回收掉。而真正的目标 Grandson 则因为 "生父" Son 死掉而被 init 收养,然后直接被人道毁灭。
|
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
void create_child()
{ pid_t son = fork(); if (son == 0) { pid_t grandson = fork(); if (grandson == 0) { printf("child: %d, parent: %d\n", getpid(), getppid()); exit(EXIT_SUCCESS); } exit(EXIT_SUCCESS); } else if (son > 0) { waitpid(son, NULL, 0); } else { perror("fork"); } } int main(int argc, char *argv[]) |
参考:《APUE》
wait/waitpid函数与僵尸进程、fork 2 times的更多相关文章
- linux 中的进程wait()和waitpid函数,僵尸进程详解,以及利用这两个函数解决进程同步问题
转载自:http://blog.sina.com.cn/s/blog_7776b9d3010144f9.html 在UNIX 系统中,一个进程结束了,但是他的父进程没有等待(调用wait / wait ...
- wait函数与waitpid函数(僵尸进程)
当子进程退出时,内核会向父进程发送SIGCHLD信号,子进程的退出是个异步事件(子进程可以在父进程运行的任何时刻终止) 子进程退出时,内核将子进程置为僵尸状态,这个进程称为僵尸进程.它只保留最小的一些 ...
- Linux进程理解与实践(四)wait函数处理僵尸进程
Wait的背景 当子进程退出的时候,内核会向父进程发送SIGCHLD信号,子进程的退出是个异步事件(子进程可以在父进程运行的任何时刻终止) 子进程退出时,内核将子进程置为僵尸状态,这个进程称为僵尸进程 ...
- C/C++网络编程8——多进程服务器端之销毁僵尸进程
上一节提到,当子进程执行结束,父进程还在执行,在父进程结束之前子进程会成为僵尸进程,那么怎么销毁僵尸进程呢?父进程主动接收子进程的返回值. 销毁僵尸进程的方法: 1:使用wait函数 2:使用wait ...
- linux系统编程之进程(三):进程复制fork,孤儿进程,僵尸进程
本节目标: 复制进程映像 fork系统调用 孤儿进程.僵尸进程 写时复制 一,进程复制(或产生) 使用fork函数得到的子进程从父进程的继承了整个进程的地址空间,包括:进程上下文.进程堆栈. ...
- 二十三、Linux 进程与信号---进程链和进程扇、守护进程和孤儿进程以及僵尸进程
23.1 进程链和进程扇 23.1.1 概念 进程链:一个父进程构建出一个子进程,子进程再构建出子子进程,子子进程构建出子子子进程.... 这种就为进程链 进程扇:一个父进程构建出多个子进程,子进程都 ...
- OS之进程管理---孤儿进程和僵尸进程
僵尸进程 当一个进程终止时,操作系统会释放其资源,不过它位于进程表中的条目还是在的,直到它的父进程调用wait():这是因为进程表中包含了进程的退出状态.当进程已经终止,但是其父进尚未调用wait() ...
- python学习笔记—— 多进程中的 孤儿进程和僵尸进程
1 基本概述 1.1 孤儿进程和僵尸进程 父进程创建子进程后,较为理想状态是子进程结束,父进程回收子进程并释放子进程占有的资源:而实际上,父子进程是异步过程,两者谁先结束是无顺的,一般可以通过父进程调 ...
- UNIX高级环境编程(9)进程控制(Process Control)- fork,vfork,僵尸进程,wait和waitpid
本章包含内容有: 创建新进程 程序执行(program execution) 进程终止(process termination) 进程的各种ID 1 进程标识符(Process Identifie ...
随机推荐
- python3之日期和时间(转载)
转载:https://www.cnblogs.com/zhangxinqi/p/7687862.html a = datetime.datetime.now() time.sleep(10) b = ...
- 【SpringBoot】SpringBoot性能优化
Spring 框架给企业软件开发者提供了常见问题的通用解决方案,包括那些在未来开发中没有意识到的问题.但是,它构建的 J2EE 项目变得越来越臃肿,逐渐被 Spring Boot 所替代.Spring ...
- [置顶] IOS用CGContextRef画各种图形(文字、圆、直线、弧线、矩形、扇形、椭圆、三角形、圆角矩形、贝塞尔曲线、图片)
首先了解一下CGContextRef: An opaque type that represents a Quartz 2D drawing environment. Graphics Context ...
- js数组对象深度复制
var deepCopy = function(o) { if (o instanceof Array) { var n = []; for (var i = 0; i < o.length; ...
- linux下如何查看所有的用户和组信息?
/etc/group 文件是用户组的配置文件. /etc/passwd 文件是用户的配置文件. 使用cat.more.less.head.tail以及vim等命令都可以查看.修改这两个配置文件. 说 ...
- 【android】模拟点击某个指定坐标作用在View上
/** * 模拟点击某个指定坐标作用在View上 * @param view * @param x * @param y */ public void clickView(View view,floa ...
- 移动端兼容 - faskclick.js
fasckclick为解决移动端300ms延迟而生 github地址为:https://github.com/ftlabs/fastclick 使用方法: 1. 原生使用(window.onload或 ...
- Jsp之神笔记
JSP笔记 Tomcatserver port: port就是指的某一个程序网络入口,Tomcat的初始化port为:8080: port的个数:256*256=65536个: 一般常见协议的缺省po ...
- python 读帧和绘图的区别
capture = cv2.VideoCapture(0) while True: #img = cv.QueryFrame(capture) ret, frame = capture.read() ...
- 优化iOS程序性能的25个方法
1. 用ARC管理内存 ARC(Automatic ReferenceCounting, 自己主动引用计数)和iOS5一起公布.它避免了最常见的也就是常常是因为我们忘记释放内存所造成的内存泄露.它自己 ...