僵尸进程最优解

前言

什么是僵尸进程?

当子进程比父进程先结束,而父进程又没有回收子进程,释放子进程占用的资源,此时子进程将成为一个僵尸进程,直到父进程结束,僵尸进程的资源才会被释放。

僵尸进程产生的原因

父子进程运行是一个异步的过程,为了使得父进程在子进程退出时,仍可以获得子进程的状态信息,Unix不会直接释放进程的所有资源。当子进程退出时,内核释放子进程的用户资源,包括打开的文件,占用的内存等,但是仍然为其保留一定的信息,包括进程号(Process ID),退出状态(Termination Status),运行时间(Runtime)等。

这样,父进程就可以通过调用wait/waitpid来获取子进程的状态信息同时释放子进程资源,但如果不调用wait/waitpid,系统资源将被占用,可能导致系统无法产生新的进程。

正文

正如上文提到的,可以使用wait/waitpid来将僵尸进程资源回收
可以在父进程中调用wait/waitpid,或者捕获SIGCHLD再调用wait/waitpid

需要注意:

  • 调用wait/waitpid函数时,如果没有僵尸子进程,但仍有子进程,父进程会阻塞,直到有子进程死亡,变成僵尸进程
  • wait/waitpid 一次返回一个子进程的状态信息,有多个进程需要调用多次
  • 多线程阻塞在wait/waitpid时,仅有一个线程会返回子进程状态信息

大多时候我们都希望父子进程异步工作,而不是阻塞等待子进程结束,下面是捕获SIGCHLD的示例:

void handle(int sig){
	printf("catch signal %d\n",sig);
	wait(NULL); // 可以传入结构体,并调用不同函数获取特定的信息,具体看手册
	printf("Child process exit\n");
}

int main(){
	int pid = fork();
	if(pid > 0){
		signal(SIGCHLD,handle);
		// 父进程工作
	}else if(pid == 0){
	// 子进程工作
	}
}

但是这里忽略了SIGCHLD信号的产生条件,SIGCHLD信号在子进程终止,挂起,被唤醒时会向父进程发出
如果子进程接收到挂起信号,父进程进入handle处理函数,父进程将阻塞在wait/waitpid

如果我们不关心子进程的执行情况,最简单直接的方法就是忽略SIGCHLD信号,让子进程结束后由init接管,init进程会释放掉所有僵尸进程的资源。

signal(SIGCHLD,SIG_IGN);

思考一下,忽略SIGCHLD信号是否对程序有影响,SIGCHLD信号产生条件:终止,挂起,唤醒

其中挂起信号(SIGSTOP),SIGKILL信号无法捕获,所以忽略SIGCHLD信号对这两个没影响
但是假如我们希望捕获SIGCONT信号,生成日志,那么我们就不能简单忽略SIGCHLD信号

个人认为更科学的做法是
使用sigaction,并设置sa_flags标志位为SA_NOCLDWAIT
这样,当子进程终止(terminate)时,子进程不会被设置为僵尸进程

struct sigaction sa;
memset(&sa,0,sizeof(sa));
sa.sa_handler = SIG_DFL;  // 也可以自定义handler函数
sa.sa_flags = SA_NOCLDWAIT;
sigaction(SIGCHLD,&sa,NULL);

tips:
当使用 -std=c99 编译时,会找不到sigaction结构体,解决方法:添加头文件<bits/sigaction.h>
也可以使用 -std=gnu99 编译

另外也有别的技巧,调用两次fork函数,然后子进程退出,孙进程由系统接管

int pid;
if ((pid = fork()) == 0){
	if ((pid = fork()) > 0)
		exit(0); // 子进程退出
	else{
		// 孙进程工作
	}
}
else{
	// 父进程工作
}

仅做记录,最好的方法还是使用sigaction
在这里插入图片描述

  • 7
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值