zoukankan      html  css  js  c++  java
  • linux系统编程之进程(四)

    今天继续研究进程相关的东东,话不多说,进入正题:

    SIGCHLD:
    关于它,之前章节的学习中已经用到了,具体可以参考博文:http://www.cnblogs.com/webor2006/p/3500972.html,这里会进一步来理解它:
     
    说明:关于信号,很快就会有一个专题来仔细研究它,现在可以简单认为:它是一种异步通知事件
    说明:如果父进程没有查询子进程的退出状态,子进程是没有办法真正完全退出的,这时子进程的状态就称为僵尸状态,该进程就叫僵尸进程
    下面就对这两个函数进行详析:
    wait:
     
    下面用具体代码来进行说明:
    #include <unistd.h>
    #include <sys/stat.h>
    #include <sys/wait.h>//提供wait函数声明
    #include <sys/types.h>
    #include <fcntl.h>
    
    #include <stdlib.h>
    #include <stdio.h>
    #include <errno.h>
    #include <string.h>
    #include <signal.h>
    
    
    #define ERR_EXIT(m) 
        do 
        { 
            perror(m); 
            exit(EXIT_FAILURE); 
        } while(0)
    
    int main(int argc, char *argv[])
    {
        pid_t pid;
        pid = fork();
        if (pid == -1)
            ERR_EXIT("fork error");
    
        if (pid == 0)
        {
            sleep(3);//子进程休眠,是为了看到父进程会等待子进程退出
            printf("this is child
    ");
            exit(100);
        }
    
        printf("this is parent
    ");
        int status;
        wait(&status);等待子进程退出
        return 0;
    }

    看一下编译运行效果,下面用动画来展现,以便能体现到wait的意义:

    从图中可以感受到,父进程虽然是已经输出了,但是一直是等到子进程退出了才退出,这也就是wait会让父进程去查子进程的退出状态,从而避免了僵尸进程的出现。

    编译运行:

    对于这些状态信息,可以通过调用系统宏来查询,下面具体来介绍下:

    用来代码来解释:

    编译运行:

    下面我们可以用abort函数,来模拟子进程非法退出的情况:

    这时再编译运行:

    实际上,对于子进程非法退出的,还可以判断得再仔细一些,因为有好几种情况可以造成子进程非法退出,如上图所示,一是因为捕获信号而终止,二是被暂停了,具体用法如下:

    编译运行:

    关于信号,由于还没有学到,所以暂停的信号就不多说了,这里就不演示暂停信号的情况了,重在理解一下获取子进程退出状态信息的用法

    【说明:上面的这些宏在sys/wait.h头文件里定义

    waitpid:
    对于上面刚学完的wait,它是等待随意的进程退出,因为一个父进程可以有多个子进程,如果只要有一个子进程退出,父进程的wait就会返回;
    而waitpid则可以等待特定的进程退出,这是两者的区别,下面就来具体学习下这个函数的用法:
     
    对于waitpid的pid参数的解释与其值有关:
    实际上可以通过查看man帮助得到这个信息:
    可以将我们之前的程序用waitpid替换一下,效果一样:
     
    也同样,用它来改装我们之前的程序,对于父进程,实际上只有一个子进程,就可以直接传子进程的id既可,只等待这个子进程:
    效果一样:
     
    比如:waitpid(-100,&status,0)的意思就是,等待进程组ID=100里面的任一一个子进程。
     
    最后,关于wait和waitpid,进行一个总结:
     另外,对于僵进程,已经被提到过好几次了,最后再来总结一下:
    僵进程:
    如何避免僵进程:
    system:
     
    实际上,它就等于用代码去执行我们在命令行中敲的那些shell命令,下面就以实际代码来认识这个函数的使用:
    编译运行:
    实际上,system()函数是调用"/bin/sh -c",如下:
    对于这个函数的使用,其实没什么难的,但是这个函数很有代表性,我们可以通过它来综合运用我们所学习东西,这样其实还是挺有意义的,接下来,会自己实现一个跟system同样的功能,来达到理解system函数的实现原理:
    #include <unistd.h>
    #include <sys/stat.h>
    #include <sys/wait.h>
    #include <sys/types.h>
    #include <fcntl.h>
    
    #include <stdlib.h>
    #include <stdio.h>
    #include <errno.h>
    #include <string.h>
    #include <signal.h>
    
    
    #define ERR_EXIT(m) 
        do 
        { 
            perror(m); 
            exit(EXIT_FAILURE); 
        } while(0)
    
    int my_system(const char *command);//自己实现有system函数声明
    
    int main(int argc, char *argv[])
    {
        my_system("ls -l | wc -w");//这里改用自己实现在system
        return 0;
    }
    
    int my_system(const char *command)
    {
        pid_t pid;
        int status;
        if (command == NULL)
            return 1;
      if ((pid = fork()) < 0)
            status = -1;//出现不能执行system调用的其他错误时返回-1
      else if (pid == 0)
        {//子进程
            execl("/bin/sh", "sh", "-c", command, NULL);//替换成sh进程
            exit(127);//如果无法启动shell运行命令,system将返回127,因为如果成功替换了之后,是不会执行到这句来的
        }
        else
        {//父进程会等到子进程执行完
            while (waitpid(pid, &status, 0) < 0)
            {
                if (errno == EINTR)//如果是被信号打断的,则重新waitpid
                    continue;
                
                status = -1;
                break;
            }
         //这时就顺利执行完了 }
    return status; }

    编译运行:

    可见,通过自己实现的system,就能够大致弄清楚它的原理,虽说程序比较少,但是五脏俱全,因为可以把自己学过的知识给运用起来。

    好了,今天的学习就到这,下次见。

  • 相关阅读:
    UML基础—结构和组成
    Hadoop完全分布式
    Hadoop完全分布式
    查看端口是否启用
    查看端口是否启用
    hadoop namenode启动失败
    hadoop namenode启动失败
    Hadoop2.7.5伪分布式安装
    Hadoop2.7.5伪分布式安装
    给用户添加sudo权限
  • 原文地址:https://www.cnblogs.com/webor2006/p/3512781.html
Copyright © 2011-2022 走看看