Linux进程浅析(下)

Linux进程浅析下

  1. 僵尸进程
  2. wait和waitpid函数

僵尸进程

看到僵尸二字很多时候我们都会想到林正英饰演的僵尸道长系列,僵尸都是一群失去了生命,但是却可以活动的尸体吧,其实在linux内核中其实也相似,这类进程也是失去生命,但是却没有被彻底回收掉的
一批进程。

 僵尸进程的概念:
子进程结束但是没有完全释放内存,在内核中(task_struct没有释放),该进程就是僵尸进程

当僵尸进程的父进程结束后就会被init进程领养,最终被回收

避免僵尸进程:
1:让僵尸进程的父进程来回收,父进程每隔一段时间来查询子进程是否回收,调用wait()或者waitpid(),通知内核释放僵尸进程。
2:采用信号SIGCHLD(singalchild)通知处理,并在信号处理程序中调用wait函数,
3:让僵尸进程成为孤儿进程,由init进程回收;

直接上代码吧,打造属于我们自己的僵尸进程,代码类似打造我们自己的孤儿进程,如果想了解什么叫孤儿进程,请参考Linux进程浅析中,里面讲解了孤儿进程

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/types.h>


int main(int argc,char * argv[]){
    pid_t pid;
    pid = fork();
    if(pid <0){
        perror("fork error\n");
        exit(EXIT_FAILURE);
    }else if(pid > 0){

    }else{
        printf("getpid:%d,getppid:%d\n",getpid(),getppid());
        exit(1);
    }
    while(1){
        sleep(1);
    }
    return 0;
}

执行结果如下所示:
这里写图片描述
子进程结束了,但是父进程处于一种等待状态,这个时候打开另外一个终端就可以看到后台的这个子进程有没有继续在运行了
这里写图片描述
从这里就可以看到,后台其实还是有一个process_zombie进程好为23863的这样的一个进程在运行并且其有一个状态为Z+,说明其子进程为僵尸状态,而父进程23862处于S+状态,说明其处于的是一种可中断的等待状态
那下面就简单了解下,怎么通过父进程来关闭释放掉僵尸进程。
也就是wait和waitpid函数的使用

wait和waitpid函数

wait函数和waitpid函数:

#include<unistd.h>
#include<wait.h>

pid_t wait(int *status);
返回:成功返回子进程ID,出错返回-1
功能:等待子进程退出并且回收,防止孤儿进程产生

pid_t waitpid(pid_t pid,int *status,int options);
返回:成功返回子进程ID,出错返回-1
功能:wait函数的非阻塞版本

区别:
在一个子进程终止前,wait函数阻塞
waitpid有一个选项,可使调用者不阻塞
waitpid等待一个指定的子进程,而wait等待所有的子进程,返回任何子进程的状态

status参数:
为空时,代表任意状态结束的子进程,
若不为空,则代表指定状态结束的子进程;

检查wait和waitpid函数返回终止状态的宏;
WIFEXITED/WEXITSTATUS(status)
若子进程正常终止,则为真
WIFSIGNALED/WTERMSIG(status)
若为异常终止子进程返回的状态,则为真
WIFSTOPED/WSTOPSIG(status)
若子进程在终止前是否暂停过,如果暂停为真,

实例代码如下所示:
if(WIFEXITED(status)){
    printf("%d",WEXITSTATUS(status)); 
}else if(WIFSTOPED(status)){
    printf("%d",WTERMSIG(status));
}else if(WIFSTOPED(status)){
    printf("%d",WSTOPSIG(status));
}else{
    printf("unknow sig\n");
}

option参数
WNOHANG
    若由pid制定的子进程没有退出则立即返回,则waitpid不阻塞,此时其返回值为0;
WUNTRACED
若某实现支持作业控制,则由pid制定的任一子进程状态已暂停,且其状态自暂停以来还未报告过,则返回其状态

实例参数如下所示:
do{
    pid = waitpid(pid,&status,WNOHANG | WUNTRACED);
    if(pid == 0) sleep(1);
}while(pid==0)
    exit(3);
    //exit(0);
如果为0 ,则为正常终止,非0为异常终止状态;
使用kill -l的时候可以查看到Linux系统的所有信号


关于waitpid的pid参数传递:
    若pid == -1  
        等待任意一个子进程
    若pid > 0
        等待其与其进程id相匹配的子进程结束
    若pid == 0
        等待其组id等于调用进程的组ID的任意子进程
    若pid < -1
        等待其组id等于pid绝对值的任一子进程

下面的代码是关于wait函数的:注意:wait函数是阻塞式的调用,即父进程会阻塞等待子进程的释放。

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/wait.h>


void outStatus(int status);
int main(int argc,char *argv[]){

    pid_t pid = fork();
    int status;

    if(pid < 0){
        perror("fork error");
        exit(1);
    }else if(pid > 0){
        //父进程执行
        pid_t child_pid = wait(&status);
        outStatus(status);
    }else {
        //子进程执行
        printf("pid:%d,ppid:%d\n",getpid(),getppid());
        exit(3);

        //异常终止法
        //int num1 = 3 ,num2  = 0;
        //int k = num1 / num2;
        //printf("k = :%d\n",k);

        //暂停终止法
        //pause();

    }


    return 0;
}   


void outStatus(int status){
    if(WIFEXITED(status)){
        printf("waitexist:%d\n",WEXITSTATUS(status));

    }else if(WIFSIGNALED(status)){
        printf("waitsinglenal:%d\n",WTERMSIG(status));
    }else if(WIFSTOPPED(status)){
        printf("waitstop:%d\n",WIFSTOPPED(status));
    }else {
        printf("unknow exit!\n");
    }

}

代码也是可以直接进行run的

下面了解一下waitpid这个函数,这个函数可以设置阻塞方式也可以设置非阻塞方式,记住如果要处理暂停状态的话,那么就必须要去使用waitpid来进行设置:

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<sys/types.h>
#include<unistd.h>
#include<sys/wait.h>

void outStatus(int status);


int main(int argc,char * argv[]){

    pid_t pid = fork();
    int status;
    if(pid < 0 ){
        perror("fork error\n");
        exit(1);
    }else if(pid > 0){
        //父进程执行的时间片
        //专门处理进行过停止状态后的进程退出
        do {    
            pid = waitpid(pid,&status,WNOHANG | WUNTRACED);
            //说明子进程没结束
            if(pid == 0){
                sleep(1);
            }
        }while(pid == 0);

        outStatus(status);
    }else {
        //子进程执行的时间片,子进程做暂停操作
        printf("getpid:%d getppid:%d\n",getpid(),getppid());
        pause();
        //或者将子进程进行永久睡眠
        //int i = 0;
        //while(++i > 0){
        //  sleep(4);
        //}
    }
    return 0;
}


void outStatus(int status){
    if(WIFEXITED(status)){
        printf("exit :%d\n",WEXITSTATUS(status));
    }else if(WIFSIGNALED(status)){
        printf("singal:%d\n",WTERMSIG(status));
    }else if(WIFSTOPPED(status)){
        printf("stop:%d\n",WIFSTOPPED(status));
    }else {
        printf("unknow exit!\n");
    }
}

可能在这里需要提到一点,就是linux系统信号相关的东西,在linux系统中。提供了相关信号,使用kill -l 进行查看。可以使用相关信号来对 进程做相应的处理,如下图所示
linux信号

具体的一下含义在linux内核中的信号相关部分,可以解释下,有点兴趣的可以自己简单搜一下。对应的是哪些含义的信号

最近相对来说也比较忙,事情也比较多,也遇到了可能作为程序员以来最不愿意看到的结果,所以有点小受挫,所以更的速度相对来说稍微慢了一点。当头一棒吧。内功还得继续修炼。
以上的代码都是可以直接进行run的。有兴趣的童鞋可以试着拷贝下去跑着玩,同时最近也想着建一个撸代码的群。也是一个学习群吧,寻找有志之士,希望能够相互学习,帮助,共同成长吧。认识的人不在多,在帮助有多深。,知识,技术本来就是一个交流的过程,只有交流,只有学习,也同时需要更多的努力,才能成为一个合格的程序员吧!!

qq群号为324652573

欢迎持续访问博客

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值