今天一位朋友去一个不错的外企面试linux开发职位,面试官出了一个如下的题目:
给出如下C程序,在linux下使用gcc编译:
#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的执行机制有一个明晰的认识。
转自:http://kb.cnblogs.com/page/76622/
我自己的理解:
从图中可以看出,主线程fork出的线程,fork的返回值就是该线程的pid,但是对于主线程fork的返回值却是0。从图中一目了然的就可以知道另外的3中情况。
ps:我的新博客地址:http://www.xinghaixu.com
相关推荐
### Linux 下 `fork()` 运行机制解析及面试题解答 #### 预备知识 在深入了解本面试题之前,我们需要掌握一些关于Linux进程管理的基础概念: 1. **进程的概念**:在Linux环境下,进程可以被视为一个正在执行的程序...
【Linux内核经典面试题详解】 1. Linux内核锁:Linux内核中主要有自旋锁和信号量两种锁机制。自旋锁用于保护短暂的、不会引起阻塞的临界区,而信号量则允许任务在无法获取锁时进入睡眠状态,适合处理可能长时间持有...
本篇文章将基于一道经典的面试题目来探讨 Linux 下进程创建机制,特别是 `fork` 函数的工作原理。该题目不仅考验应试者对进程创建的理解,还涉及了对进程间关系的认识。 #### 题目描述 假设有一段 C 语言程序,在 ...
在Linux和C语言的面试中,...以上只是部分知识点,实际上Linux和C语言的面试题可能涵盖更广泛的内容。在准备面试时,应确保自己不仅理解这些概念,还能在实际问题中应用它们。不断实践和深入研究,是提升技能的关键。
本文将详细解析"嵌入式软件开发IO部分面试题"中的四个关键概念:进程与线程的区别、静态库与动态库的区别、标准IO与文件IO的区别,以及fork函数、僵尸进程和孤儿进程。 首先,我们来看进程和线程的差异。进程是操作...
### 互联网各厂运维方向面试题汇总解析 #### 一、TCP/IP协议栈知识点解析 **1. TCP大量TIME_WAIT状态的原因及解决方法** - **原因分析**:当客户端和服务端之间的TCP连接正常关闭时,服务端会在最后一个ACK包发送...
根据给定的信息,本文将对“驱动面试题”这一主题进行深入探讨,主要涉及通用输入输出(GPIO)的概念、触摸屏工作原理以及Linux C语言中`ls`命令的执行原理等几个方面。 ### 1. GPIO (General Purpose Input/Output) ...
### 嵌入式软件开发与Linux开发中的进程与线程知识点详解 #### 一、进程与线程基本概念 1. **进程**与**线程**的概念及其区别: - **进程**:指计算机中运行的一个应用程序实例,拥有独立的内存空间、执行环境和...
UNIX高级编程中的网络编程涉及许多概念和细节,这些都是IT专业人士在面试过程中经常遇到的。下面将详细解释上述提到的知识点。 1. **ping命令使用的报文**:ping命令使用的是ICMP回显请求和回显应答报文。ICMP是...
### C++与操作系统面试题解析:Fork函数详解 #### 题目背景与解析 在计算机编程领域,特别是涉及操作系统级别的程序设计时,`fork()` 函数是极为重要的一个概念。它允许一个进程创建一个新的几乎完全一样的副本,...
### 嵌入式软件面试知识点详解 #### 进程和线程间通信方式 进程间的通信(IPC)包括管道(pipe)、消息队列(message queue)、共享内存(shared memory)、信号量(semaphore)、套接字(socket)等方式。线程间的...
三、Linux相关面试题 1. **Linux基础**:熟悉常用的Linux命令,如ls、cd、mv、grep、sed、awk等。 2. **文件系统**:理解EXT4等文件系统的原理,知道如何挂载和卸载文件系统。 3. **进程管理**:理解进程的概念,...
以下是这些面试题的详细解析: 1. 使用Linux epoll模型,水平触发模式(Level-Triggered)时,当socket可写时,会持续触发可写事件。处理方法通常有两种: - 第一种方法是每次需要写数据时将socket加入epoll,接收...
根据给定的百度技术面试题,我们可以深入探讨一系列与IT技术相关的知识点,这些知识点涵盖了C++编程、Linux操作系统、Shell脚本、网络协议等多个领域,是IT从业者面试时需掌握的核心技能。 ### 1. C++特性 C++是一...
### 华为复试面试题解析 #### 网络部分 **1. 一般网络确认方式** - **知识点概述:** - 网络确认是确保数据在网络中正确传输的过程。 - 常见的网络确认方式包括TCP三次握手、四次挥手等。 - **详细解释:** -...
以上是对LINUX内核经典面试题的详细解答,这些问题涵盖了Linux内核的基本概念、内存管理、进程管理、文件系统以及设备驱动等核心知识点。对于深入理解Linux内核的工作原理和技术细节具有重要的指导意义。