僵死进程的产生?解决方案?

什么是僵死进程,产生原因

当fork()产生一个新进程的时候,子进程一般会和父进程同时运行。当子进程结束时,它与父进程的关系还会保持,直到父进程也正常终止或者wait,子进程才结束。因此,进程中代表子进程的表项不会立即释放。虽然子进程不能正常运行,但是它仍然存在于系统之中,因此退出码还要保存起来,以便于父进程之后wait调用。
这种情况称已经结束了但是还是不能释放的子进程为僵尸进程

如何解决僵死进程

方式一:wait

wait函数的形式

pid_t wait(int *stat_loc)

返回值为子进程的pid,如果 stat_loc 不为空,则内核保存的子进程的状态信息将会写入它指向的位置。
注意:

wait()函数会使父进程在函数调用处挂起,当子进程结束之后,父进程才会继续执行wait之后的代码。
wait函数将父子进程分离开来,让本来并发执行的父子进程变成了异步执行。

方式二:waitpid

waitpid()函数的形式:

pid_t waitpid(pid_t pid,int *stat_loc,int options);

返回值为清理掉的子进程的pid,如果为-1,标识没有子进程被清理。
pid参数含义:

pid>0     回收指定ID的子进程
pid=-1    回收任意子进程
pid=0     回收和当前调用waitpid一个组的所有子进程
pid<-1    回收指定进程组内的任意子进程

options选项:

WNHONG
如果pid指定的子进程没有结束,则waitpid()函数直接返回0,而非阻塞在这个函数上;如果结束了,则返回该子进程的进程号。
WUNTRACED
如果子进程进入暂停状态,则马上返回

waitpid函数相比于wait函数,除了能等待指定的进程,还能在等待进程的同时通过设置options选项为WNOHANG让父进程不会在waitpid函数中阻塞。

因此,如果想让父进程周期性的检查某个特定的子进程是否结束,就可以使用waitpid()。

方式三:信号

信号量是一种软中断机制。我们知道,任何一个子进程结束,内核都会给父进程发送一个SIGCHLD信号,如果我们在父进程定义一个信号处理函数,在函数中进行wait操作或者waitpid操作,当任何一个子进程结束的时候,都会触发signal函数,这样我们就可以通过signal+wait的方法,更加灵活的处理僵尸进程了。
自定义信号:
在这里插入图片描述
信号:
SI_DFL 默认,不做反应
SIG_IGN 忽略,不做响应
改变信号的响应方式即可。
在这里插入图片描述

方式四:两次fork

首先我们了解一下孤儿进程,孤儿进程正好和僵尸进程相反,孤儿进程是父进程先于子进程结束,这时,子进程就会成为一个孤儿进程,孤儿进程会立即被init收养,完成善后操作,期间不需要人工的参与。

因此两次fork解决僵尸进程的思路如下:

当父进程fork以后,产生一个子进程,在子进程中再进行fork,会产生一个孙子进程,我们可以让子进程立即退出,然后在父进程里面wait保证子进程不会成为僵尸进程,然后我们的孙子进程失去了父亲,变成了一个孤儿进程,被init收养,init会处理孙子进程的善后操作。我们要执行的代码就可以放进孙子进程里面了。

按理来说,这种方法比上述三种方法都要繁琐,但是这种方法在服务器中经常会被用到。这是因为前几种方法在子进程结束的时候都会对父进程造成消耗。而两次fork的方法,只有在连接的时候造成消耗(子进程立即退出,和连接几乎同时发生),而后面的孙子进程完全脱离了服务器进程,不会再对服务器有任何负担。

原文链接:https://blog.csdn.net/qq_42214953/article/details/105579607

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值