进程控制之进程等待

进程等待

父进程等待子进程退出之后获取它的退出信息并且回收其子进程内存资源,这里的退出信息分为正常退出和异常退出.

为什么需要进程等待?

  • 避免产生僵尸进程而造成内存泄漏
  • 回收子进程资源,获取子进程退出信息

等待的方式

方法一: wait 函数方法

#include <sys/types.h>
#include <sys/wait.h>
pid_t wait(int*status);//函数原型
返回值:成功返回等待进程 pid,失败返回 -1
参数为输出型参数,可以获取子进程退出状态,不关心则可以设置成为NULL

注意:一个 wait 函数只能等待一个子进程,如果有多个子进程需要多次调用 wait 函数

在这里插入图片描述
我们可以看到 wait 的返回值是被等待的子进程 pid;如果输出型参数不为NULL,代码又是如何呢?
在这里插入图片描述
我们可以看到有两个

  • WIFEXITED(status): 若子进程正常终止,则返回的状态为真(用来查看进程是否是正常退出)

  • WEXITSTATUS(status): 若 WIFEXITED 非零,提取子进程退出码(用来查看进程的退出码)

方法二:waitpid 函数等待

  • 函数原型:pid_ t waitpid(pid_t pid, int *status, int options);

  • 返回值:当正常返回的时候 waitpid 返回收集到的子进程的进程PID,如果设置了选项 WNOHANG, 而调用中 waitpid 发现没有已退出的子进程可收集,则返回0;如果调用中出错,则返回 -1

参数:pid 、status、options

第一个参数:pid 如果等于 -1,会等待任一个子进程,与wait等效;如果 pid >0 等待指定 pid 子进程

第二个参数:设置为WIFEXITED(status) 若子进程正常终止,则返回的状态为真(查看进程是否是正常退出), 用 WEXITSTATUS(status)提取子进程退出码

第三个参数:设置为 WNOHANG 表示非阻塞,若pid指定的子进程没有结束,则 waitpid() 函数不等待直接返回0;若正常结束,则返回该子进程的ID ,如果参数为0表示阻塞式等待,在没有等待到子进程前不会返回.

如果子进程已经退出,调用wait/waitpid时,wait/waitpid会立即返回,并且释放资源,获得子进程退出信息

如果在任意时刻调用wait/waitpid,子进程存在且正常运行,则进程可能阻塞

如果不存在该子进程,则立即出错返回。

阻塞式等待
在这里插入图片描述
在这里插入图片描述

获取子进程 status

上面我们谈到两个宏,他们的具体实现方式是怎么样呢?退出码在内存中的存储方式又是怎样的?

wait 和 waitpid,都有一个status参数,该参数是一个输出型参数,由操作系统填充。如果传递NULL,表示不关心子进程的退出状态信息。否则,操作系统会根据该参数,将子进程的退出信息反馈给父进程。status不能简单的当作整形来看待,可以当作位图来看待,具体细节如下图(只研究status低16比特位):
正常终止:
在这里插入图片描述
0x7f 的二进制码为 0111 1111 所以如果status与0x7f==0的话,那就说明低七位存储的都是0,如果七位存储的都是零就说明子进是正常终止的,否则就是异常退出的;但是他的退出状态存在了后面的8-15位;所以得先右移8位,然后再与0xff (1111 1111)所得到的就是退出码;在这里插入图片描述
异常终止:被信号所杀
在这里插入图片描述在这里插入图片描述

方法三:采用wait 和 waitpid 函数清理僵尸进程,可能会影响父进程自身的工作效率,所以可以采用信号处理函数的方式清理僵尸进程

当子进程退出后,会自动给父进程发送一个 SIGCHLD 信号,只不过父进程采取忽略的方式,所以我们可把处理方式改为 调用 wait 函数,这样只要子进程退出后,父进程就会捕捉到这个信号.

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
void handler(int sig){
	pid_t id;
	while((id = waitpid(-1, NULL, WNOHANG)) > 0){
		printf("wait child success: %d\n", id);
	}
	printf("child is quit! %d\n", getpid());
}
int main(){
	signal(SIGCHLD, handler);
	pid_t cid;
	//child
	if((cid = fork()) == 0){
		printf("child : %d\n", getpid());
		sleep(3);
		exit(1);
	}
	while(1){
		printf("father proc is doing some thing!\n");
		sleep(1);
	}
	return 0;
}
僵尸进程产生原因
  • 子进程结束后向父进程发出 SIGCHLD信号,父进程默认忽略了它 ,并没有接收到子进程发给自己的信号!!

  • 父进程没有调用 wait() 或 waitpid() 函数来等待子进程的结束

僵尸进程的危害

会占用系统资源无法释放,如果有很多的话会严重影响服务器的性能,导致无法创建进程,甚至会造成内存泄露

子进程的维护退出状态本身就是要用数据维护,也属于进程基本信息,所以保存在task_struct中,Z状态一直不退出,PCB一直都要维护

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序猿的温柔香

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值