前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >他们说,这段代码你能看得懂她的开始,却猜不中她的结尾。

他们说,这段代码你能看得懂她的开始,却猜不中她的结尾。

作者头像
KINGYT
发布2020-10-30 11:47:17
3400
发布2020-10-30 11:47:17
举报

看下小姐姐,舒缓下心情先。


好,现在回到我们的主题,看下下面这段代码,你觉得它会输出几个#号呢?

这个问题来自于我们技术群里的一位同学的提问,为了给大家一个思考时间,我们先不说结果,先再看下另一位可爱的小妹妹。


啊,好可爱啊,为啥我选择了技术,而没去学画画


好,不知道你想得怎么样了呢?

我们先来执行下,看下其具体输出。

看到没,8个,不知道你有没有猜对呢?

可为什么是8个呢,你要说2个我能理解,3个我也能理解,为什么偏偏是这么夸张的8个

其实这道题目主要考察两个点,第一个点就是fork的作用,如果你不理解fork,那你肯定认为输出的个数就是2个。

fork的作用其实就是拷贝当前进程,然后创建一个原样的子进程,子进程开始时执行的代码,就是父进程调用fork之后的代码。

对于我们上面的题目来说,子进程就是进入了下一次for循环。

详细的fork文档可以参考下面的链接:

https://man7.org/linux/man-pages/man2/fork.2.html

因为fork函数创建子进程,进而也会有#号输出,把这个考虑在内的话应该是3个#号,因为主进程会输出2个,主进程第一次for循环创建的子进程,在其进入到下一次循环时又会输出一个。

其他的因为主进程,或者是该子进程调用fork方法,创建的进一步的子进程再进入到for循环时,因为不满足 i < 2,会直接跳出循环,也就是说不会再输出#号。

那这样说也应该是3个#号啊,为什么是8个呢?

这里就涉及到了第二个知识点,printf。

为了减少系统调用次数,提高程序性能,我们每次调用printf时,并不会立即触发一次系统调用,而是会先写到printf的buffer区,如果buffer区满了,或者说写入字符中有\n换行符,才会真正的触发一次系统调用,将我们buffer中的printf的内容输出到控制台。

这也是有时我们写程序时,经常会发现明明调用了输出方法,但控制台上就是没有输出的一个常见原因。

好,再次回到我们的题目。

由上图我们可以看到,我们在for循环里调用的printf,都是没有加上\n换行符的,我们只有在进程结束前的printf才加上,也就是说,for循环里的printf,只是把我们的内容放到了它的buffer中,并没有真正输出。

那有意思的事就来了。

当我们后面再调用fork时,fork可是拷贝当前进程的全部内存的,这可是包括printf的buffer区的,举例来说,当我们主进程执行第二次for循环,调用fork时,此时的printf的buffer里已经有两个#号了,此时fork一个子进程,子进程中的相应buffer区里也会有这两个#号。

当主进程或子进程退出之前,遇到最后一个带有\n换行符的printf时,就会把buffer中现有的那两个#号输出出来,即每一个进程都会因为同样的原因,最终输出2个#号。

再看下我们的代码,算上主进程,一共创建了4个进程,那最终输出的可不就是8个#号嘛。

小知识,大学问!

不知道你有没有猜中这样的结尾呢?


写文章不易,如果可以的话,欢迎大家转发或给个在看,没关注的也可以关注下,希望以后能给大家带来更多的惊艳文章。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2020-10-17,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Linux内核及JVM底层相关技术研究 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档