• Linux多进程


    一、进程的概念

    什么是进程?进程这个概念是针对系统而不是针对程序员的,对程序员来说,我们面对的概念是程序,当输入指令执行一个程序的时候,对系统而言,它将启动一个进程。

    进程就是正在内存中运行中的程序,Linux下一个进程在内存里有三部分的数据,就是“代码段”、”堆栈段”和”数据段”。”代码段”,顾名思义,就是存放了程序代码。“堆栈段”存放的就是程序的返回地址、程序的参数以及程序的局部变量。而“数据段”则存放程序的全局变量,常数以及动态数据分配的数据空间(比如用new函数分配的空间)。

    系统如果同时运行多个相同的程序,它们的“代码段”是相同的,“堆栈段”和“数据段”是不同的(相同的程序,处理的数据不同)。

    二、进程的编号

    1、查看进程

    ps 查看当前终端的进程。

    在这里插入图片描述

    ps -ef 查看系统全部的进程。

    ps -ef |more 查看系统全部的进程,结果分页显示。

    在这里插入图片描述

    UID :启动进程的操作系统用户。

    PID :进程编号。

    PPID :进程的父进程的编号。

    C :CPU使用的资源百分比。

    STIME :进程启动时间。

    TTY :进程所属的终端。

    TIME :使用掉的CPU时间。

    CMD :执行的是什么指令。

    ps -ef |grep book查看系统全部的进程,然后从结果集中过滤出包含“book”单词的记录。程序员用得最多的指令就是这个了。

    在这里插入图片描述

    2、getpid库函数

    getpid库函数的功能是获取本程序运行时进程的编号。

    函数声明:

    pid_t getpid();
    

    函数没有参数,返回值是进程的编号,pid_t就是typedef int pid_t。

    示例(book251.cpp)

    /*
     * 程序名:book251.cpp,此程序用于演示获取程序运行时的进程编号
     * 作者:C语言技术网(www.freecplus.net) 日期:20190525
    */
    #include <stdio.h>
    #include <sys/types.h>
    #include <unistd.h>
    
    int main()
    {
      printf("本程序的进程编号是:%d
    ",getpid());
      sleep(30);    // 是为了方便查看进程在shell下用ps -ef|grep book251查看本进程的编号。
    }
    

    运行效果

    在这里插入图片描述

    在book251运行时,切换到其它的窗口,执行ps -ef|grep book251可以查看进程,如下。

    在这里插入图片描述

    注意两个细节:

    1)进程的编号是系统动态分配的,相同的程序在不同的时间执行,进程的编号是不同的。

    2)进程的编号会循环使用,但是,在同一时间,进程的编号是唯一的,也就是说,不管任何时间,系统不可能存在两个编号相同的进程。

    三、多进程

    fork在英文中是“分叉”的意思。为什么取这个名字呢?因为一个进程在运行中,如果使用了fork函数,就产生了另一个进程,于是进程就“分叉”了,所以这个名字取得很形象。下面就看看如何具体使用fork函数,这段程序演示了使用fork的基本框架。

    函数声明:

    pid_t fork();
    

    fork函数用于产生一个新的进程,函数返回值pid_t是一个整数,在父进程中,返回值是子进程编号,在子进程中,返回值是0。

    示例(book252.cpp)

    /*
     * 程序名:book252.cpp,此程序用于演示用fork生成一个子进程。
     * 作者:C语言技术网(www.freecplus.net) 日期:20190525
    */
    #include <stdio.h>
    #include <sys/types.h>
    #include <unistd.h>
    
    int main()
    {
      printf("本程序的进程编号是:%d
    ",getpid());
    
      int ipid=fork();
    
      sleep(1);       // sleep等待进程的生成。
    
      printf("pid=%d
    ",ipid);
    
      if (ipid!=0) printf("父进程编号是:%d
    ",getpid());
      else printf("子进程编号是:%d
    ",getpid());
    
      sleep(30);    // 是为了方便查看进程在shell下用ps -ef|grep book252查看本进程的编号。
    }
    

    运行效果

    在这里插入图片描述

    查看进程情况,出现了两个book进程。

    在这里插入图片描述
    初学者可能用点接受不了现实。

    1)一个函数(fork)返回了两个值?

    2)if和else中的代码能同时被执行?

    那么调用这个fork函数时发生了什么呢?fork函数创建了一个新的进程,新进程(子进程)与原有的进程(父进程)一模一样。子进程和父进程使用相同的代码段;子进程拷贝了父进程的堆栈段和数据段。子进程一旦开始运行,它复制了父进程的一切数据,然后各自运行,相互之间没有影响。

    fork函数对返回值做了特别的处理,调用fork函数之后,在子程序中fork的返回值是0,在父进程中fork的返回值仍是原进程的编号,程序员可以通过fork的返回值来区分父进程和子进程,然后再执行不同的代码。

    示例(book253.cpp)

    /*
     * 程序名:book253.cpp,此程序用于演示用fork生成一个子进程后,父子进程进入不同的流程。
     * 作者:C语言技术网(www.freecplus.net) 日期:20190525
    */
    #include <stdio.h>
    #include <sys/types.h>
    #include <unistd.h>
    
    void fatchfunc()  // 父进程流程的主函数
    {
      printf("我是老子,我喜欢孩子他娘。
    ");
    }
    
    void childfunc()  // 子进程流程的主函数
    {
      printf("我是儿子,我喜欢西施。
    ");
    }
    
    int main()
    {
      if (fork()>0) { printf("这是父进程,将调用fatchfunc()。
    "); fatchfunc();}
      else { printf("这是子进程,将调用childfunc()。
    ");  childfunc();}
    
      sleep(1); printf("父子进程执行完自己的函数后都来这里。
    "); sleep(1);
    }
    

    运行效果

    在这里插入图片描述

    在上文上已提到过,子进程拷贝了父进程的堆栈段和数据段,也就是说,在父进程中定义的变量子进程中会复制一个副本,fork之后,子进程对变量的操作不会影响交父进程,父进程对变量的操作也不会影响子进程。

    示例(book254.cpp)

    /*
     * 程序名:book254.cpp,此程序用于演示用fork之后的父子进程在内存中是独立的数据空间。
     * 作者:C语言技术网(www.freecplus.net) 日期:20190525
    */
    #include <stdio.h>
    #include <sys/types.h>
    #include <unistd.h>
    
    int ii=10;
    
    int main()
    {
      int jj=20;
    
      if (fork()>0) 
      { 
        ii=11;jj=21; sleep(1);  printf("父进程:ii=%d,jj=%d
    ",ii,jj);
      }
      else
      { 
        ii=12;jj=22; sleep(1);  printf("子进程:ii=%d,jj=%d
    ",ii,jj);
      }
    }
    

    运行效果

    在这里插入图片描述

    四、课后作业

    1)编写一个多进程程序,验证子进程是复制父进程的内存变量,还是父子进程共享内存变量?

    2)编写一个示例程序,由父进程生成10个子进程,在子进程中显示它是第几个子进程和子进程本身的进程编号。

    3)编写示例程序,由父进程生成子进程,子进程再生成孙进程,共生成第10代进程,在各级子进程中显示它是第几代子进程和子进程本身的进程编号。

    4)利用尽可能少的代码快速fork出更多的进程,试试看能不能把linux系统搞死。

    5)ps -ef |grep book251命令是ps和grep两个系统命令的组合,各位查一下资料,了解一下grep命令的功能,对程序员来,grep是经常用到的命令。

    五、版权声明

    C语言技术网原创文章,转载请说明文章的来源、作者和原文的链接。
    来源:C语言技术网(www.freecplus.net)
    作者:码农有道

    如果文章有错别字,或者内容有错误,或其他的建议和意见,请您留言指正,非常感谢!!!

  • 相关阅读:
    javascript作用域
    [翻译]Review——How JavaScript works:The building blocks of Web Workers
    [转]Shared——回调函数是什么
    由上一个血案引发的关于property和attribute关系的思考
    RN canvas画布大小之谜
    [转]Tips——Chrome DevTools
    Algorithm——无重复字符的最长子串
    [翻译]Review——The Inner Workings Of Virtual DOM
    Tips——单页面内的多重跳转路由使用
    [转]Shared——Javascript中的call详解
  • 原文地址:https://www.cnblogs.com/wucongzhou/p/12497995.html
Copyright © 2020-2023  润新知