linux下fork的运行机制

<!-- @page { margin: 2cm } P { margin-bottom: 0.21cm } -->

如下 C 程序,在 linux 下使用 gcc 编译:
1 #include "stdio.h"
2 #include "sys/types.h"
3 #include "unistd.h"
int main()
4 {
5     pid_t pid1;
6     pid_t pid2;
7     pid1 = fork();
8     pid2 = fork();
10     printf( "pid1:%d, pid2:%d/n" , pid1, pid2);
11 }
      
要求如下:
      
已知从这个程序执行到这个程序的所有进程结束这个时间段内,没有其它新进程执行。
      1
、请说出执行这个程序后,将一共运行几个进程。
      2
、如果其中一个进程的输出结果是“ pid1:1001, pid2:1002” ,写出其他进程的输出结果(不考虑进程执行顺序)。
     
学习 linux fork 的运行机制
预备知识
      1
、进程可以看做程序的一次执行过程。在 linux 下,每个进程有唯一的 PID 标识进程。 PID 是一个从 1 32768 的正整数,其中 1 一般是特殊进程 init ,其它进程从 2 开始依次编号。当用完 32768 后,从 2 重新开始。
      2
linux 中有一个叫进程表的结构用来存储当前正在运行的进程。可以使用“ ps aux” 命令查看所有正在运行的进程。
      3
、进程在 linux 中呈树状结构, init 为根节点,其它进程均有父进程,某进程的父进程就是启动这个进程的进程,这个进程叫做父进程的子进程。
      4
fork 的作用是复制一个与当前进程一样的进程。新进程的所有数据(变量、环境变量、程序计数器等)数值都和原进程一致,但是是一个全新的进程,并作为原进程的子进程。
解题的关键
      
有了上面的预备知识,我们再来看看解题的关键。我认为,解题的关键就是要认识到 fork 将程序切成两段。看下图:



      上图表示一个含有 fork 的程序,而 fork 语句可以看成将程序切为 A B 两个部分。然后整个程序会如下运行:

      step1 、设由 shell 直接执行程序,生成了进程 P P 执行完 Part. A 的所有代码。

      step2 、当执行到 pid = fork(); 时, P 启动一个进程 Q Q P 的子进程,和 P 是同一个程序的进程。 Q 继承 P 的所有变量、环境变量、程序计数器的 当前 值。

      step3 、在 P 进程中, fork() Q PID 返回给变量 pid ,并继续执行 Part. B 的代码。

      step4 、在进程 Q 中,将 0 赋给 pid ,并继续执行 Part. B 的代码。

      这里有三个点非常关键 :

      1 P 执行了所有程序,而 Q 只执行了 Part. B ,即 fork() 后面的程序。(这是因为 Q 继承了 P PC- 程序计数器)

      2 Q 继承了 fork() 语句执行时当前的环境,而不是程序的初始环境。

      3 P fork() 语句启动子进程 Q ,并将 Q PID 返回,而 Q 中的 fork() 语句不启动新进程,仅将 0 返回。

解题


      下面利用上文阐述的知识进行解题。这里我把两个问题放在一起进行分析。

      1 、从 shell 中执行此程序,启动了一个进程,我们设这个进程为 P0 ,设其 PID XXX (解题过程不需知道其 PID )。

      2 、当执行到 pid1 = fork(); 时, P0 启动一个子进程 P1 ,由题目知 P1 PID 1001 。我们暂且不管 P1

      3 P0 中的 fork 返回 1001 pid1 ,继续执行到 pid2 = fork(); ,此时启动另一个新进程,设为 P2 ,由题目知 P2 PID 1002 。同样暂且不管 P2

      4 P0 中的第二个 fork 返回 1002 pid2 ,继续执行完后续程序,结束。所以, P0 的结果为“ pid1:1001, pid2:1002”

      5 、再看 P2 P2 生成时, P0 pid1=1001 ,所以 P2 pid1 继承 P0 1001 ,而作为子进程 pid2=0 P2 从第二个 fork 后开始执行,结束后输出“pid1:1001, pid2:0”

      6 、接着看 P1 P1 中第一条 fork 返回 0 pid1 ,然后接着执行后面的语句。而后面接着的语句是 pid2 = fork(); 执行到这里, P1 又产生了一个新进程,设为P3 。先不管 P3

      7 P1 中第二条 fork P3 PID 返回给 pid2 ,由预备知识知 P3 PID 1003 ,所以 P1 pid2=1003 P1 继续执行后续程序,结束,输出“ pid1:0, pid2:1003”

      8 P3 作为 P1 的子进程,继承 P1 pid1=0 ,并且第二条 fork 0 返回给 pid2 ,所以 P3 最后输出“ pid1:0, pid2:0”

      9 、至此,整个执行过程完毕。

      所得答案:

      1 、一共执行了四个进程。( P0, P1, P2, P3

      2 、另外几个进程的输出分别为:

      pid1:1001, pid2:0

      pid1:0, pid2:1003

      pid1:0, pid2:0

      进一步可以给出一个以 P0 为根的进程树:



 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值