看下小姐姐,舒缓下心情先。
好,现在回到我们的主题,看下下面这段代码,你觉得它会输出几个#号呢?
这个问题来自于我们技术群里的一位同学的提问,为了给大家一个思考时间,我们先不说结果,先再看下另一位可爱的小妹妹。
啊,好可爱啊,为啥我选择了技术,而没去学画画
!
好,不知道你想得怎么样了呢?
我们先来执行下,看下其具体输出。
看到没,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个#号嘛。
小知识,大学问!
不知道你有没有猜中这样的结尾呢?
写文章不易,如果可以的话,欢迎大家转发或给个在看,没关注的也可以关注下,希望以后能给大家带来更多的惊艳文章。
本文分享自 Linux内核及JVM底层相关技术研究 微信公众号,前往查看
如有侵权,请联系 cloudcommunity@tencent.com 删除。
本文参与 腾讯云自媒体同步曝光计划 ,欢迎热爱写作的你一起参与!