(转)linux下fork的运行机制
转载http://www.cnblogs.com/leoo2sk/archive/2009/12/11/talk-about-fork-in-linux.html
给出如下C程序,在linux下使用gcc编译:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
#include "stdio.h"#include "sys/types.h"#include "unistd.h"int main(){ pid_t pid1; pid_t pid2; pid1 = fork(); pid2 = fork(); printf("pid1:%d, pid2:%d\n", pid1, pid2);} |
要求如下:
已知从这个程序执行到这个程序的所有进程结束这个时间段内,没有其它新进程执行。
1、请说出执行这个程序后,将一共运行几个进程。
2、如果其中一个进程的输出结果是“pid1:1001, pid2:1002”,写出其他进程的输出结果(不考虑进程执行顺序)。
明显这道题的目的是考察linux下fork的执行机制。下面我们通过分析这个题目,谈谈linux下fork的运行机制。
预备知识
这里先列出一些必要的预备知识,对linux下进程机制比较熟悉的朋友可以略过。
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为根的进程树:

验证
下面我们去linux下实际执行这个程序,来验证我们的答案。
程序如下图:

用gcc编译、执行后结果如下:

由于我们不太可能刚巧碰上PID分配到1001的情况,所以具体数值可能和答案有所差别。不过将这里的2710看做基数的话,结果和我们上面的解答是一致的。
总结
应该说这不是一道特别难或特别刁钻的题目,但是由于fork函数运行机制的复杂性,造就了当两个fork并排时,问题就变得很复杂。解这个题的关键,一是要对linux下进程的机制有一定认识,二是抓住上文提到的几个关于fork的关键点。朋友说,这个题给的时间是5分钟,应该说时间还算充裕,但是在面试的场合下,还是很考验一个人对进程、fork的掌握程度和现场推理能力。
希望本文能帮助朋友们对fork的执行机制有一个明晰的认识。
(转)linux下fork的运行机制的更多相关文章
- 【Linux下进程机制】从一道面试题谈linux下fork的运行机制
今天一位朋友去一个不错的外企面试linux开发职位,面试官出了一个如下的题目: 给出如下C程序,在linux下使用gcc编译: #include "stdio.h" #includ ...
- 从一道面试题谈linux下fork的运行机制
http://www.cnblogs.com/leoo2sk/archive/2009/12/11/talk-about-fork-in-linux.html
- 【转】Linux下Fork与Exec使用
Linux下Fork与Exec使用 转自 Linux下Fork与Exec使用 一.引言 对于没有接触过Unix/Linux操作系统的人来说,fork是最难理解的概念之一:它执行一次却返回两个值.for ...
- Linux下fork()、vfork()、clone()和exec()的区别
转自Linux下fork().vfork().clone()和exec()的区别 前三个和最后一个是两个类型.前三个主要是Linux用来创建新的进程(线程)而设计的,exec()系列函数则是用来用指定 ...
- Linux下Fork与Exec使用
Linux下Fork与Exec使用 一.引言 对于没有接触过Unix/Linux操作系统的人来说,fork是最难理解的概念之一:它执行一次却返回两个值.fork函数是Unix系统最杰出的成就之一, ...
- [转帖]Linux下fork函数及pthread函数的总结
Linux下fork函数及pthread函数的总结 https://blog.csdn.net/wangdd_199326/article/details/76180514 fork Linux多进程 ...
- linux下,一个运行中的程序,究竟占用了多少内存
linux下,一个运行中的程序,究竟占用了多少内存 1. 在linux下,查看一个运行中的程序, 占用了多少内存, 一般的命令有 (1). ps aux: 其中 VSZ(或VSS)列 表示,程序占用 ...
- Linux下Fork与Exec
一.引言 对于没有接触过Unix/Linux操作系统的人来说,fork是最难理解的概念之一:它执行一次却返回两个值.fork函数是Unix系统最杰出的成就之一,它是七十年代UNIX早期的开发者经过长期 ...
- Linux下Java 编译运行说明
命令行环境下Java编译运行 1. java的运行机制的基本概念: 源文件 也就是我们熟知的.java文件. 类文件 .class文件是编译器由.java文件编译而成.众所周知,Java的跨平台性在 ...
随机推荐
- Visual Studio 2012 编译C++显示cl命令
为了用newlisp来实现VC编译,以便用我的Emacs开发VC程序,而不需要再打开VS 2012, 需要自己实现命令行的编译.我不需要nmake,因为我想直接了解VC编译器,以便今后更好的驾驭它. ...
- World Wind Java开发之十五——载入三维模型
之前的一篇博客是关于载入粗三维模型的,见http://blog.csdn.net/giser_whu/article/details/43452703,这个地方还存在着不能载入纹理的问题,一直没呢解决 ...
- Android-IM架构设计
###1. 架构总览 ###2. 模块介绍 ####2.1 协议封装与任务流程 #####1) 协议与任务的封装 a. 协议有协议头(协议头因为格式相同,被抽象出来)和协议体组成,协议有两类:请求协议 ...
- CPU使用率和Load Average的关系
看了几篇博客总结的区别,自己终于明白了含义,在这里将理解总结一下: 对于定义和解释,感觉淘测试上的更容易理解: 引用如下: CPU使用率: 一段时间内CPU的使用状况,从这个指标可以看出某一段时间内 ...
- Sqlserver in 实现 参数化查询 XML类型
原文: http://www.cnblogs.com/tangruixin/archive/2012/04/23/2465917.html 1:如果参数是int类型: declare @a xmlse ...
- (转)IIS5.1的安装配置并发布ASP.NET网站
最近跟老师做一个桥梁养护系统的项目,要求用VS2008+Sql Server2000,服务器用IIS.由于之前做过的ASP.NET项目都是用的VS内置的服务器,并没有使用过IIS,第一次搭,花了几个小 ...
- PowerDesigner与UML建模应用
一. PD简介 PowerDesigner 是一个集所有现代建模技术于一身的完整工具,它集成了强有力的业务建模技术.传统的数据库分析和实现,以及UML对象建模.通过了元数据的管理.冲突分析和真正的 ...
- UISearchDisplayController简单使用
最近在做一个简单的app入门,中间有一个页面用到了搜索框,本来以为很简单的控件,没想到用到的时候才发现很麻烦. 搜索框使用过程大约有以下几个状态:不活跃-活跃-输入关键词-根据关键词动态列出相关结果- ...
- OpenGL ES 2.0 限定符
限定符 说明 作用 attribute 一般用于各个顶点各不相同的量,如顶点位置.颜色等 属性限定符,修饰的变量用来接收渲染管线传递进顶点着色器的当前顶点的各种属性值. 只能用来修饰符点数标量,浮点数 ...
- 基于nginx的rtmp的服务器(nginx-rtmp-module)
一,首先下载安装nginx需要依赖的库文件: 1.1,选定源码目录 选定目录 /usr/local/RTMP cd /usr/local/RTMP 1.2,安装PCRE库 cd /usr/local/ ...