zoukankan      html  css  js  c++  java
  • fork函数的理解1

    一、一个进程的构成

       一个进程由正文段(即代码段)、用户数据段以及系统数据段。

    其中系统数据段又称进程控制块(PCB),是给操作系统进行调度用的。系统数据段中存放了关于这个进程的:PID 、PPID、优先级、占用的资源、该进程的状态等等。

    fork函数用于进程创建。

    看下面一段代码

       1:  #include <stdio.h>
       2:  #include <unistd.h>
       3:  #include <stdlib.h>
       4:  #include <sys/types.h>
       5:   
       6:   
       7:  int main(void)
       8:  {
       9:      int a = 0;
      10:      pid_t pid;
      11:   
      12:   
      13:      if((pid = fork()) == -1)
      14:      {
      15:          printf("fork error!\n");
      16:          exit(-1);
      17:      }
      18:   
      19:      if(pid == 0)
      20:      {
      21:          a++;
      22:          printf("child result= %d, pid=%d, ppid=%d, a=%d, &a=%p\n",pid,getpid(),getppid(),a,&a);
      23:      }
      24:      else
      25:      {
      26:          printf("parent  result= %d, pid=%d, ppid=%d, a=%d, &a=%p\n",pid,getpid(),getppid(),a,&a);
      27:   
      28:      }
      29:      return 0;
      30:  }

    比如此刻有一个进程P1刚开始执行该程序,但执行到fork函数,进入fork函数体内,此时程序计数器PC(PC中存放的是返回地址,当返回后会把返回值给了pid这个变量)压栈, fork会创建一个P1的子进程P2,P2同样也是有三部分构成(正文段(即代码段)、用户数据段以及系统数据段),这三段基本上与其父进程完全一样,包括压到栈的PC,不同的是他们的pid以及ppid。P2的ppid是P1的进程号,而P1的ppid就是shell的进程号。可以这么理解,此时在内存中有如下两个同样的部分。

                       父PS1的                                                                                 子PS2的

    image

    image

                         

    执行  pstree  命令后

    image

    他们的家族关系是:

    image

    可以看到,P1的父进程是bash。

    所以当执行完fork函数后,P1和P2都返回,PC出栈,但是P2并不再执行fork函数和fork函数前面的程序,而是将fork的返回值赋值给变量pid。

    看一下输出:

    image

    二、注意

    • 当子进程先于父进程结束,子进程的状态变为 Z,又称“僵尸态”,即虽然结束了,但是还占有一些资源。子进程的资源回收由其父进程负责。
    • 当父进程先于子进程结束,子进程有init进程负责回收。但是此时子进程不在受shell控制,变为后台进程,假如子进程中有getchar等需要用户输入,getchar会返回-1。

    当出现第二种情况时,gnome-terminal输出会有点乱:

    image

    • 从输出可以看出,两次输出的a的地址相同,原因:

    image

    即: 子进程和父进程中的a的虚拟地址相同,但是物理地址不同。其中内存管理单元MMU完成虚拟内存和物理内存的转换。

  • 相关阅读:
    [HAOI2006] 旅行
    Vue 2 --v-model、局部组件和全局组件、父子组件传值、平行组件传值
    Flume简介及安装
    MySQL数据目录更改及相关问题解决方案
    更换gcc工具链
    支持多种类型的数据集合作为数据源
    23种设计模式--中介者模式-Mediator Pattern
    PID算法原理 一图看懂PID的三个参数
    内存四区
    趣味算法讲解
  • 原文地址:https://www.cnblogs.com/pengdonglin137/p/2943281.html
Copyright © 2011-2022 走看看