孤儿进程与僵尸进程

1.概念

孤儿进程:一个父进程退出,而它的一个或多个子进程还在运行,那么那些子进程将成为孤儿进程。孤儿进程将被init进程(进程号为1)所收养,并由init进程对它们完成状态收集工作。

僵尸进程:一个进程使用fork创建子进程,如果子进程退出,而父进程并没有调用wait或waitpid获取子进程的状态信息,那么子进程的进程描述符仍然保存在系统中。这种进程称之为僵死进程

 

2.产生

实例1:子进程、父进程、孤儿进程

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>

#define child_debug(_fmt_, ...)  printf("[ child] l:%d,"_fmt_"\r\n",__LINE__,##__VA_ARGS__)	
#define parent_debug(_fmt_, ...) printf("[parent] l:%d,"_fmt_"\r\n",__LINE__,##__VA_ARGS__)
int main()
{
    pid_t pid;
    //创建一个进程
    printf("#####fork test#######\n");
    pid = fork();
    printf("fork()  pid=%d\n",pid);
    //创建失败
    if (pid < 0)
    {
        perror("fork error:");
        exit(1);
    }
    //子进程点击打开链接
    if (pid == 0)
    {
        child_debug(" child process");
        //输出进程ID和父进程ID
        child_debug(" pid:%d\tppid:%d",getpid(),getppid());
        child_debug(" sleep five seconds");
        //睡眠5s,保证父进程先退出
        sleep(5);
        //子进程成孤儿进程,被init进程收养
        child_debug("pid:%d\tppid:%d",getpid(),getppid());
        child_debug(" child exited");
    }
    //父进程
    else
    {
        parent_debug(" child processid=%d",pid);
        //父进程睡眠1s,保证子进程输出进程id
        sleep(1);
        parent_debug("#########commod ps##########");
        system("ps");
        parent_debug("parent exited");
    }
    return 0;
}

实例2:僵尸进程

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>

#define child_debug(_fmt_, ...)  printf("[ child] l:%d,"_fmt_"\r\n",__LINE__,##__VA_ARGS__)	
#define parent_debug(_fmt_, ...) printf("[parent] l:%d,"_fmt_"\r\n",__LINE__,##__VA_ARGS__)
int main()
{
    pid_t pid;
    //创建一个进程
    printf("#####fork test#######\n");
    pid = fork();
    printf("fork()  pid=%d\n",pid);
    //创建失败
    if (pid < 0)
    {
        perror("fork error:");
        exit(1);
    }
    //子进程
    if (pid == 0)
    {
        child_debug(" child process");
        //输出进程ID和父进程ID
        child_debug(" pid:%d\tppid:%d",getpid(),getppid());
        //保证子进程先退出,而父进程没有wait/waitpid获取子进程状态,将成为僵尸进程
        parent_debug("#########commod ps##########");
        system("ps");
        child_debug("pid:%d\tppid:%d",getpid(),getppid());
        child_debug(" child exited");
    }
    //父进程
    else
    {
        parent_debug(" child processid=%d",pid);
        //父进程睡眠10s,保证子进程先退出
        sleep(10);
        parent_debug("#########commod ps##########");
        system("ps -o pid,ppid,state,tty,command");
        parent_debug("parent exited");
    }
    return 0;
}

实例3:避免僵尸进程方法

1、wait/waitpid,但是会使父进程阻塞;(可考虑子进程创建线程,在线程中wait/waitpid)
2、fork twice, 用孙子进程去完成子进程的任务(注意这种方法的使用情景
3、signal(SIGCHLD,SIG_IGN), 并不是所有系统都兼容 --(备注:忽略子进程退出信号)
4、sigaction + SA_NOCLDWAIT, 并不是所有系统都兼容--(没使用过)
5、推荐方法:在signal handler中调用 waitpid (下面的例子能说明用 waitpid 而不用 wait的原因),这样父进程不用阻塞

注意:每一种方法都有它适用的场合,比如方法 5 适用于 one-request-one-process 的网络服务器程序。

方法1:

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <sys/wait.h>
#define child_debug(_fmt_, ...)  printf("[ child] l:%d,"_fmt_"\r\n",__LINE__,##__VA_ARGS__)	
#define parent_debug(_fmt_, ...) printf("[parent] l:%d,"_fmt_"\r\n",__LINE__,##__VA_ARGS__)
int main()
{
    pid_t pid;
    //创建一个进程
    printf("#####fork test#######\n");
    pid = fork();
    printf("fork()  pid=%d\n",pid);
    //创建失败
    if (pid < 0)
    {
        perror("fork error:");
        exit(1);
    }
    //子进程
    if (pid == 0)
    {
        child_debug(" child process");
        //输出进程ID和父进程ID
        child_debug(" pid:%d\tppid:%d",getpid(),getppid());
        child_debug(" sleep five seconds");
        parent_debug("#########commod ps##########");
        system("ps");
        child_debug("pid:%d\tppid:%d",getpid(),getppid());
        child_debug(" child exited");
    }
    //父进程
    else
    {
        parent_debug(" child processid=%d",pid);
        int status=0;
        int pid_ret=waitpid(pid,&status,0);
        //根据status状态值,确认子进程退出是否正常?coredump?还是SIGPIPE?等问题
        parent_debug(" child pid=%d,pid_ret=%d",pid,pid_ret);
        //WIFEXITED return non-zero if child exited normally 
        parent_debug("WIFEXITED(status) == %d",WIFEXITED(status));
        //WEXITSTATUS get the return code
        parent_debug(" The return code WEXITSTATUS(status) == %d",WEXITSTATUS(status));
        //returns true if the child process was terminated by a signal
        parent_debug(" WIFSIGNALED(status) == %d",WIFSIGNALED(status));
        //returns  the  number of the signal that caused the child process to terminate.  
        //This macro should only be employedif WIFSIGNALED returned true.
        parent_debug(" WTERMSIG(status) == %d", WTERMSIG(status));
        //returns true if the child produced a core dump.  This macro should only be employed if WIFSIGNALED returned  true.
        //This  macro is not specified in POSIX.1-2001 and is not available on some Unix implementations (e.g., AIX, SunOS).
        // Only use this enclosed in #ifdef WCOREDUMP ... #endif.
        parent_debug(" WCOREDUMP(status) == %d", WCOREDUMP(status));
        //returns true if the child process was stopped by delivery of a signal; this is only possible if the call was  done
        //using WUNTRACED or when the child is being traced (see ptrace(2)).
        parent_debug(" WIFSTOPPED(status) == %d",WIFSTOPPED(status));
        //returns the number of the signal which caused the child to stop.  This macro should only be employed if WIFSTOPPED
        //      returned true
        parent_debug(" WSTOPSIG(status) == %d",WSTOPSIG(status));
        // (since Linux 2.6.10) returns true if the child process was resumed by delivery of SIGCONT
        parent_debug(" WIFCONTINUED(status) == %d",WIFCONTINUED(status));
        parent_debug("parent exited");
    }
    return 0;
}

参考资料:

避免产生僵尸进程的N种方法:http://blog.csdn.net/duyiwuer2009/article/details/7964795

孤儿进程与僵尸进程[总结]:https://www.cnblogs.com/Anker/p/3271773.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值