孤儿进程和僵尸进程

一、进程

      进程可以看做程序的一次执行过程。在linux下,每个进程都会被分配一个唯一的数字编号,我们称之为进程标识符或PID。PID是一个从1到32768的正整数,其中1一般是特殊进程init,其它进程从2开始依次编号。当用完32768后,从2重新开始。

       在一台单处理器的计算机上,同一时间只有一个进程可以运行,其他程序处于就绪状态,该状态表示程序只要得到CPU就可以运行了。每个进程运行的时间是有限的,我们称作时间片,时间片是相当短暂的,这就给我们一种程序在同时运行的错觉。Linux内核用进程调度器来决定下一个时间片分配给那个进程,它的判断依据是根据进程的优先级。高优先级的进程运行得更频繁,但长期不间断运行的进程,优先级会变低,同时,低优先级的进程随着时间的推移,优先级会不断提升,直到其能够被执行。

 二、父进程与子进程

       子进程指的是由另一进程(对应称之为父进程)所创建的进程。一个进程可能下属多个子进程,但最多只能有1个父进程,而若某一进程没有父进程,则可知该进程很可能由内核直接生成。

 三、孤儿进程

      父进程先结束,子进程还在运行,该子进程就叫做孤儿进程。 孤儿进程会被 init 进程领养,init 进程就变成了该孤儿进程的父进程。

      这样做是为了释放子进程占用的系统资源。因为进程结束之后,能够自己释放用户区所占用的内存空间,但它释放不了PCB(进程控制块)所占的系统资源,该资源必须由父进程释放。

四、僵尸进程

       子进程先于父进程结束,而父进程又没有回收子进程,释放子进程占用的系统资源,此时子进程将成为一个僵尸进程。

       如果大量的产生僵尸进程,将因为没有可用的进程号而导致系统不能产生新的进程. 此即为僵尸进程的危害,应当避免。

五、例子

上面的这道程序会使父函数阻塞10秒,此时子进程早已结束,而父进程无任何作为,这时该子进程就会变成僵尸进程。

     由上图我们可以看到,光标还在不停闪烁,表示在子进程运行完输出 B 后,父进程还在运行,于是子进程后面有了一个   defunct 标志,这就说明它现在是一个僵尸进程。

     当然,当父进程正常结束后,init 进程像收养孤儿进程一样负责回收该僵尸进程占用的资源,如此僵尸进程就不存在了。

四、僵尸进程的应对方法

1、wait()函数

wait()函数一般用在父进程中等待回收子进程的资源,而防止僵尸进程的产生。

#include<sys/types.h>

#include<sys/wait.h>

pid_t wait(int* status);  //阻塞函数,其条件是有子进程结束

参数:

    status:传出参数。判断子进程是如何结束的,正常结束还是被某个信号杀死了。

                   若设置为NULL,则说明不关心该子进程的退出情况,只是想释放其资源。

    使用相应的宏获取子进程的退出状态:

    WIFEXITED(status):该值非0,进程正常退出。

    WEXITSTATUS(status):若上面的宏为真。使用此宏获取进程的退出状态,即exit(n)中n这个数字

    例如: if(WIFEXITED){printf("%d",WEXITSTATUS(STATUS));} //打印出进程的退出码

    WIFSIGNALED(status):该值非0,进程异常终止。

    WTERMSIG(status):若上面的宏为真,使用此宏获取使子进程退出的信号的编号 

    例如:if(WIFSIGNALED(status)){"%d",WTERMSIG(status);}   //打印出该信号的编号

    

返回值:

    -1:回收失败,说明已经没有子进程了。如果还有子进程存在,该函数会一直阻塞

    >0: 回收的子进程pid

注意:

     wait()函数一次只能回收一个已结束的子进程。若程序有多个子进程,则需要循环调用该函数。因为wait的返回值是终止进程的进程PID,所以父进程总能知道哪一个子进程终止了。

例子:

如上面的程序,我们只是添加了一个wait()函数,这时候即使子进程结先束了,父进程还在运行,是不会出现僵尸进程的,因为当子进程结束后,wait()函数将其回收了。

4025 是wait()函数返回的回收的子进程pid

注意:wait()的参数一定要写,即使不需要也要把NULL写进去,否则返回值会已一直是 -1,因为出错了。

 

2、waitpid()函数

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

参数:

    pid

        等于-1:   回收任一子进程,与wait()函数等效

         大于0:   回收其进程ID与参数pid相等的子进程

         等于0 :回收当前进程组任一子进程

         大于 -1: 回收其组ID等于参数pid的绝对值的任一子进程。

    status:子进程的退出状态,用法同wait()函数的参数

    options:设置为WNOHANG,则函数为非阻塞的; 设置为0,函数为阻塞的

返回值:

    >0: 返回回收的子进程的pid

    -1:无子进程、调用被某个信号中断、选项参数无效等

    0:参数options被设置为WNOHANG,且子进程正在运行。

因为waitpid()函数在不设置第三个参数的情况下是阻塞的,所以可以用来等待某个特定进程的结束。

wait与waitpid区别:

  • 在一个子进程终止前, wait()使其调用者阻塞,而waitpid()的第三参数若设置为WNOHANG,可使调用者不阻塞。
  • waitpid()并不等待第一个终止的子进程—它有若干个选择项,可以控制它所等待的特定进程。
  • 实际上wait()函数可以看做是waitpid()函数的一个特例。waitpid(-1,&status, 0);

3、SIGCHLD信号

     子进程结束时,会向父进程发送一个 SIGCHLD 信号,系统默认是忽略这个信号,所以只要父进程对这个信号进行捕获,并在信号的捕捉函数中调用 wait() 函数或 waitpid() 函数以取得进程ID和其终止状态,释放其资源,就可以保证不出现僵尸进程。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值