一道面试题引发的头脑风暴(既有趣,又无趣的fork)

4 篇文章 0 订阅
1 篇文章 0 订阅

从昨天到现在一直在想一个跟fork有关的测试题,这个测试考察了逻辑运算知识以及对fork的理解,据说是一道什么EMC的测试题,这个题是我从学习群里看到的,还真别说这题把我头都搞胀了,这种题就是纯逻辑题,对fork的理解程度如何,fork的返回值有两个,就让问题变得很抽象。经过我的不懈坚持,今天终于把这个题目背后的逻辑,以及技巧悟透了,想分享给大家,网上的很多帖子我都不想说啥,不管对与错,直接复制粘贴,有啥用呢,你自己都没理解透,还写什么文章去误人子弟。废话不多说,接下来直接进入正题:
原题是这样的 :

int main(int agrc,char* argv[])
{
	fork();		//第一个fork
	fork() && fork() || fork();
	fork();		//最后一个fork
}

问一共创建了多少个子进程,别看这简单的三条语句,背后的逻辑把我虐的,大家看到这个题目第一反应估计会想到Linux下跑一下这个程序,没错我也是这么干的,我一运行,之后查看了一下进程数,除去父进程一共创建了19个子进程,你们可以试试这段测试代码看我说的是不是19个,图我就不贴了,懒,哈哈哈。

测试创建了多少个子进程的代码

int main()
{
	fork();		//第一个fork
	fork() && fork() || fork();
	fork();		//最后一个fork
	while(1);	//防止父进程退出,观察不到现象,加个while(1)
}

查看创建的子进程指令

ps -ef

以上步骤你就会发现确确实实是创建了19个子进程,别再跟我讲父进程了,人家题目就是问创建了多少个子进程,你说20,赶紧倒回去审题,而且我觉得你可能连最基本的父子进程这个概念都不清楚,所以好好努力吧。

那么你会问这19个子进程到底是怎么来的,请听我细细道来:

你看到代码注释的:第一个fork最后一个fork
这两句代码是父子进程都会去执行的代码,而且不需要考虑返回值。
好,那我们知道第一个fork执行完,总共有两个进程吧,一个父进程,一个子进程,那现在的关键是要知道最后一个fork执行之前一共有多少个子进程,也就是 fork() && fork() || fork()总共会创建多少个子进程,如果我们能把这跳语句创建的子进程数算出来,那么结果也就出来了

好,现在把问题拆分逐个分析,第一个fork之后,一个是父进程,一个是子进程,子进程和父进程,遵循读时共享,写时复制的原则,可以理解为子进程就是父进程的克隆体一样,代码段完全一样,也就是父子会去执行同一份代码,具体的执行流程还要看fork的返回值,了解了这个以后我们再来分析

接下来就是父子进程都会去执行 fork() && fork() || fork() 这条语句,
我们只要分析其中任何一个进程的执行结果就可以知道最后的结果,为什么是这样子的,前面我们讲了子进程是父进程的副本,那么第一次fork出来的子进程可以看成是第二个父进程,就是从代码执行层面上去这么认为,实际上他们还是有一些差别的,那么,父进程是怎么去执行的呢我画了个图,清晰的描述了这个执行的过程

在这里插入图片描述

上面的图我解释一下,首先父进程调用标号为1的fork,创建了一个子进程对应图中的蓝色部分,又因为fork有两个返回值,父进程返回值大于0,子进程返回值为0,如果返回值是大于0说明是父进程,那么父进程就会去调用标号为2的fork再创建一个子进程,对应图中的红色部分;如果返回值为0说明是子进程(蓝色部分),那么子进程(蓝色部分)就会调用标号为3的fork创建一个子进程,对应于图中的紫色部分。又因为调用标号为2的fork创建了子进程后,返回值也有两个,如果返回值是0,那么子进程(红色部分)还会调用一次标号为3的fork,再创建一个子进程,对应图中橘黄色部分。为什么咧,就是因为这一步卡死了很多人,你想想,新创建出来的子进程是不是从下一条代码开始运行,父进程调用完标号为2的fork之后创建的子进程(红色部分),这个标号为2的fork是不是也有两个返回值,如果是父进程返回值大于0,这一 整条 fork() && fork() || fork() 语句执行完毕;如果返回值为0,那么说明是子进程,但是这个子进程的下一条语句是标号为3的fork,因为始终记住,新创建出来的进程一定是从当前位置的下一条代码处开始执行,换句话说,前面的代码是啥我管不管,不管的。理解这一点就足够了,正因为是子进程返回值是0,才会去执行标号为3的fork,正因为是用了 || 这个运算符,如果不用 || 那又会是另一种结果,至此,我已经把整个逻辑讲清楚了,也就是一个进程在执行 这条 fork() && fork() || fork() 语句的时候总共新创建了4个子进程。又因为第一个fork出来的子进程是父进程的副本,从代码逻辑层面完全可以看做是第二个父进程,所以 fork() && fork() || fork() 这条语句执行完毕,总共就新创建了9个子进程,后面的不用我再详细说了。

现在把题目改改如果是下面这段代码:

int main(int agrc,char* argv[])
{
	fork();		//第一个fork
	fork() && fork() && fork() || fork();
	fork();		//最后一个fork
}

结果是多少个子进程?

一样的分析方法

我先把图扔给你,你自己去分析一遍
在这里插入图片描述
在这里插入图片描述
发现规律没有,下次遇到了同样的问题麻烦把我教的介绍给别人,哈哈哈哈哈哈哈哈哈

我们讲就要把它讲透,不管你怎么出,老子都秒杀的地步,不说秒杀的地步,至少画图能画出来,把抽象的东西给你整的明明白白的,再来一个:

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值