L010Linux和androidNDK之linux避免僵尸进程,子进程退出的处理

L010Linux和androidNDK之linux避免僵尸进程,子进程退出的处理

如果你在程序中fork出一个子进程,没有好好处理子进程退出后的相关事宜,那么就有可能召唤出传说中进程界的僵尸---僵尸进程!!!

什么是僵尸进程

一个进程在调用exit命令结束自己的生命的时候,其实它并没有真正的被 僵尸进程销毁, 而是留下一个称为僵尸进程(Zombie)的数据结构(系统调用exit,它的作用是 使进程退出,但也仅仅限于将一个正常的进程变成一个僵尸进程,并不能将其完全销毁)

僵尸进程是怎么样产生

在Linux进程的状态中,僵尸进程是非常特殊的一种,它已经放弃了几乎所有内存空间,没有任何可执行代码,也不能被调度,仅仅在进程列表中保留一个位置,记载该进程的退出状态等信息供其他进程收集,除此之外,僵尸进程不再占有任何内存空间。它需要它的父进程来为它收尸。

如果他的父进程没安装SIGCHLD信号处理函数调用wait或waitpid()等待子进程结束,又没有显式忽略该信号,那么它就一直保持僵尸状态,如果这时父进程结束了,那么init进程自动会接手这个子进程,为它收尸,它还是能被清除的。

但是如果父进程是一个循环,不会结束,那么子进程就会一直保持僵尸状态,这就是为什么系统中有时会有很多的僵尸进程。系统所能使用的进程号是有限的,如果大量的产生僵死进程,将因为没有可用的进程号而导致系统不能产生新的进程.

异步回收僵尸进程:

fork()之后,子进程从父进程获取了一份拷贝,和父进程分别独立运行,僵尸进程的产生是因为父进程没有给子进程“收尸”造成的,又可以根据危害程度分为下述两类:
总体来说:当子进程结束之后,但父进程未结束之前,子进程将成为僵尸进程。
(1)当子进程结束之后,但父进程未结束之前,子进程将成为僵尸进程,父进程结束后僵尸被init进程回收。
(2)如果子进程结束了,但是父进程始终没有结束,那么这个僵尸将一直存在,而且随着exec,僵尸越来越多。

相关回收进程的函数

#include<sys/types.h>
#include<sys/wait.h>

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

其中 wait(&status);等价于waitpid(-1, &status, 0);

waitpid()会暂时停止目前进程的执行,直到有信号来到或子进程结束
如果在调用 waitpid()时子进程已经结束,则 waitpid()会立即
返回子进程结束状态值。 子进程的结束状态值会由参数 status 返回,
而子进程的进程识别码也会一起返回。如果不在意结束状态值,则
参数 status 可以设成 NULL。参数 pid 为欲等待的子进程识别码,
其他数值意义如下:

pid<-1 等待进程组识别码为 pid 绝对值的任何子进程。
pid=-1 等待任何子进程,相当于 wait()。
pid=0 等待进程组识别码与目前进程相同的任何子进程。
pid>0 等待任何子进程识别码为 pid 的子进程。

参数options提供了一些额外的选项来控制waitpid,参数 option 可以为 0 或可以用"|"运算符把它们连接起来使用

#include <stdio.h>   
#include <stdlib.h>   
#include <signal.h>   
#include <unistd.h>   
#include <sys/wait.h>   
    
void handler(int num) {   
    //我接受到了SIGCHLD的信号啦   
    int status;   
    int pid = waitpid(-1, &status, WNOHANG);   
    if (WIFEXITED(status)) {   
        printf("The child %d exit with code %d\n", pid, WEXITSTATUS(status));   
    }   
}   
    
int main() {   
    //子进程的pid   
    int c_pid;   
    int pid;   
    
    signal(SIGCHLD, handler);   
    
    if ((pid = fork())) {   
        //父进程   
        c_pid = pid;   
        printf("The child process is %d\n", c_pid);   
    
        //父进程不用等待,做自己的事情吧~   
        int i=0;
        for ( i = 0; i < 16; i++) {   
            printf("Do parent things.\n");   
            sleep(1);   
        } 

        printf("Do parent end\n"); 
    
        exit(0);   
    } else {   
        //子进程   
        printf("I 'm a child.\n");   
        sleep(2);   
        exit(0);   
    }   
} 

子进程的结束状态

WIFEXITED/WEXITSTATUS/WIFSIGNALED
If the exit status value (*note Program Termination::) of the child  
process is zero, then the status value reported by `waitpid' or `wait'  
is also zero. You can test for other kinds of information encoded in  
the returned status value using the following macros. These macros are  
defined in the header file `sys/wait.h'.  
-- Macro: int WIFEXITED (int STATUS)  
     This macro returns a nonzero value if the child process terminated  
     normally with `exit' or `_exit'.  
-- Macro: int WEXITSTATUS (int STATUS)  
     If `WIFEXITED' is true of STATUS, this macro returns the low-order

8 bits of the exit status value from the child process. *Note  
     Exit Status::.  
-- Macro: int WIFSIGNALED (int STATUS)  
     This macro returns a nonzero value if the child process terminated  
     because it received a signal that was not handled. *Note Signal  
     Handling::

子进程的结束状态返回后存于status,如下有几个宏可判别结束情况

WIFEXITED(status)如果子进程正常结束则为非0值。  
WEXITSTATUS(status)取得子进程exit()返回的结束代码,一般会先用WIFEXITED 来判断是否正常结束才能使用此宏。  

WIFSIGNALED(status)如果子进程是因为信号而结束则此宏值为真 

WTERMSIG(status)取得子进程因信号而中止的信号代码,一般会先用WIFSIGNALED 来判断后才使用此宏。  
WIFSTOPPED(status)如果子进程处于暂停执行情况则此宏值为真。一般只有使用WUNTRACED 时才会有此情况。  
WSTOPSIG(status)取得引发子进程暂停的信号代码,一般会先用WIFSTOPPED 来判断后才使用此宏。


kill -STOP 1234 进程暂停。
kill -CONT 1234     进程继续

参考链接

  1. 异步回收fork出的子进程(僵尸进程)
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • Linux 进程管理与程序开发 进程是Linux事务管理的基本单元,所有的进程均拥有自己独立的处理环境和系统资源,...
    JamesPeng阅读 2,527评论 1 14
  • 又来到了一个老生常谈的问题,应用层软件开发的程序员要不要了解和深入学习操作系统呢? 今天就这个问题开始,来谈谈操...
    tangsl阅读 4,200评论 0 23
  • 一、进程的创建和调度 相关概念: 最基础的计算机动作被称为指令(instruction)。 程序(program)...
    穹蓝奥义阅读 4,767评论 0 6
  • O 昨天和茵子去看了招商公园1872的商住两用的LOFT,地段不错,小区环境很好、房子不错(可改小复式)、配套设施...
    红鞋子跳跳跳阅读 340评论 13 3
  • 燕儿在蓝天里飞, 看它们的羽翼。 看它们的羽翼, 有时候急燥, 有时候悠闲。 燕儿在蓝天里飞, 夕阳在它们身上。 ...
    君兮阅读 248评论 5 0