专栏首页架构说一个很有趣的fork面试程序,和大家分享下经验

一个很有趣的fork面试程序,和大家分享下经验

这两天逛了下酷壳大神的blog(http://coolshell.cn/articles/7965.html),偶然看到一个关于fork小问题,虽然之前想通了,不过还是值得回味并且和大家分享下的。

大家有兴趣可以想想,下面输出了多少个“g”?

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>

int main(void)
{
   int i;
   for(i=0; i<2; i++){
      fork();
      printf("g");
   }

   wait(NULL);
   wait(NULL);

   return 0;
}

也许你很快就说,那么简单,第一次循环,fork后2个进程,第二次再fork出4个,一共6个进程,肯定是6个“g”

恭喜你,如果我是面试官,那么你已经跪了 = =

答案:会输出8个“g”

有一个很重要的东西是,在fork()的调用处,整个父进程空间会原模原样地复制到子进程中,包括指令,变量值,程序调用栈,环境变量,缓冲区,等等。

等等!!什么,你说全部复制过去?那么我可以解释为: 上面的那个程序为什么会输入8个“-”,这是因为printf(“-“);语句有buffer

我们来试试printf的缓冲区:

#include <stdio.h>
#include <unistd.h>    //for sleep()

int main(void)
{
    printf("/nstart the dead loop/n");
    while(1)
    {    
        printf("/b->");
        fflush(stdout);//刷新输出缓冲区
        usleep(100000);
    }
    return 1;
}

哦哦!!如果不做fflush这个动作,上边的输出便不会显示到屏幕上咯? 除非其中有换行操作或者缓冲区,这也许就是所谓的“到终端行规程”!

呃呃,不要脱离了重点,我们还是回到刚才的fork问题上~

既然我们知道了printf有缓冲区,那么,又如何?

容我引用下酷壳大神美丽的图解:

你可以清楚的看到,用阴影框标注出来的两个“最终版子进程(i=2)”

他们在fork拷贝的时候,就将 parent的缓冲区一并拷贝过去,这时“g”还在缓冲区 那么,在输出的时候,两个子进程才一并把“g”从缓冲区输出来,那么是不是两个子进程没人多输出了一个? 1+1+1+1+12+12=8个

OK,我知道你和我一样可能有点懵懵的,我改下程序咯~

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>

int main(void)
{
   int i;
   for(i=0; i<2; i++){
      fork();
      printf("g  ppid=%d, pid=%d, i=%d ", getppid(), getpid(), i);
   }

   wait(NULL);
   wait(NULL);

   return 0;

你可以gcc下这个程序,在我的电脑里输出是这样的:

g  ppid=3082, pid=3128, i=0 g  ppid=3128, pid=3130, i=1 
g  ppid=3128, pid=3129, i=0 g  ppid=3129, pid=3131, i=1 
g  ppid=3128, pid=3129, i=0 g  ppid=3128, pid=3129, i=1 
g  ppid=3082, pid=3128, i=0 g  ppid=3082, pid=3128, i=1

可以看到ppid为3082 pid为3128的输出有3次 同样的,ppid为3128 pid为3129的输出有3次

你将显然发现,原本i=0时应该只会有两个“g”被输出,但是现在居然诡异地多出了两个?到底是哪两个呢? 我索性标注下这个输出结果吧~

(1)g  ppid=3082, pid=3128, i=0 (5)g  ppid=3128, pid=3130, i=1 
(2)g  ppid=3128, pid=3129, i=0 (6)g  ppid=3129, pid=3131, i=1 
(3)g  ppid=3128, pid=3129, i=0 (7)g  ppid=3128, pid=3129, i=1 
(4)g  ppid=3082, pid=3128, i=0 (8)g  ppid=3082, pid=3128, i=1

明显的,(1)和(4)是“不可能”有两个的,(2)和(3)也是,现在你知道了吧,i=0时的两个进程,在下一次fork的时候各自成为了下一个父进程,在这一次fork时,他们的信息被完全复制到了子进程,那么最后一步每一个子进程缓冲区里还存有多余的“g”(见上图)

你还可以用pstree -p | grep fork命令试下 可以得出一个树状的结构:

$ pstree -p | grep fork
|-bash(3082)-+-fork(3128)-+-fork(3129)---fork(3131)
|            |            `-fork(3130)

那么,最后我们再试试,在printf一个g的后面加上一个换行符(或者fflush)

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>

int main(void)
{
   int i;
   for(i=0; i<2; i++){
      fork();
      printf("g\n");
   }

   wait(NULL);
   wait(NULL);

   return 0;
}

输出的结果将是换行的6个“g 原因就在于,每一次换行,缓冲区的“g”,就会把数据“刷”出缓冲区

(其实或是EOF,或是缓中区满,或是文件描述符关闭,或是主动flush,或是程序退出)

下次大家在面试的时候如果遇到这个问题,相信都可以迎刃而解了吧 ~~~ (再次感谢酷壳大神,大家对我的看法如果有问题欢迎交流!)

本文分享自微信公众号 - 架构说(JiaGouS)

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2021-07-27

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 刚从阿里面试回来已拿到offer想和大家分享一下(阿里面试经验)

    前不久刚从阿里面试回来,做的准备工作也是刷题和不断的充实自己的技术,其实目前阿里的面试题并不是现在流传的那样,不过还算好顺利拿到了offer,下面来跟大家分享一...

    美的让人心动
  • 腾讯开源的使用秘籍,你值得拥有

    腾讯开源经历了5年的发展,越来越多的优秀项目成为开源项目,供广大开发者学习与使用。我们看到,腾讯的工程师们已经被开源的力量唤醒。微信团队开源了绝大部分微信的代码...

    腾讯开源
  • 一个GO语言性能问题的发现和解决

    事情起因于公司一位同事在内部邮件组中post了一个问题,一个使用了go1.8.3写的业务程序跑了一段时间后出现部分goroutine卡在等待一个锁ForkLoc...

    李海彬
  • 几个 GitHub 上算法开源项目,超 2W 的关注

    算法(Algorithm)在百度百科里是指解题方案的准确而完整的描述,是一系列解决问题的清晰指令,算法代表着用系统的方法描述解决问题的策略机制 。算法对于每个程...

    开发者技术前线
  • 译丨如何为开源软件做出贡献

    前段时间参加了2020年1月11日Node party线下分享,justjavac 大佬分享的主题就是:《如何融入并贡献开源》,感触颇多。今天又看到一篇讲关于如...

    Nealyang
  • 译 | 如何为开源代码库作出贡献——进阶途径

    如果你和我一样,希望为开源软件做出贡献,又不敢将第一个 pull request 发送至其他团队的代码仓库。

    coder_koala
  • 一道FORK的面试

    作者:陈皓 出处:https://coolshell.cn/articles/7965.html

    Linux阅码场
  • git与github在ubuntu下的使用

    最近开始使用git对kohana3的文档做一些补充的工作,使用了git 和 github ,从了解到使用,还是有一点距离,下面是总结的一些方法。

    大江小浪
  • Tensorflow入门教程(十九)——基于VNet的前列腺分割案例

    今天我将分享如何用Tensorflow实现VNet模型,并实现基于MR图像的前列腺分割的例子。

    医学处理分析专家
  • Tensorflow入门教程(二十三)——前列腺分割比赛top9之路

    在前面篇章中我分享过用2D版本和3D版本的VNet来进行MR图像的前列腺分割,为了验证分割模型的鲁棒可靠性,我在测试数据上进行了分割并在网上提交分割结果,在差不...

    医学处理分析专家
  • 用Python+小程序实现诗词大会的飞花令

    在2018年下半年的某一天,偶然观看了《中国诗词大会》节目的飞花令环节。当时作为语音行业一员对此十分感兴趣,想着能不能用程序实现一个,思考技术方案的时候发现最大...

    Crossin先生
  • GitHub上获得26236个Star的Java面试项目,你想要么?

    对于很多人来说,找到一份工作不是问题,但找到一个合适而满意的工作,却不那么简单。有些人虽然很有实力但是往往卡在面试环节。

    Java团长
  • GitHub上获得26236个Star的Java面试项目,看看你都会几个部分?

    对于很多人来说,找到一份工作不是问题,但找到一份合适而满意的工作,却不那么简单。有些人虽然很有实力但是往往卡在面试环节……

    Java后端技术
  • 最强学习资料:国内多所重点大学课程攻略

    或许每个经历过大学生涯的人都会有这样的感受:曾经努力收集各种课程资料,但在修完一门课程之后却会发现遗漏了很多重点内容。每一代前辈总结出的经验也常常因为无处传承而...

    机器之心
  • 据说精通 Git 的程序员,都用过这个开源项目

    Git是一个 “分布式版本管理工具”,一个精通Git的程序员,会帮你在履历上加不少分,而且对你日常的工作效率也会有很大的帮助

    杰哥的IT之旅
  • 测试仓库推介(上)

    最近加入了一个GitHub团队,地址:https://github.com/JunManYuanLong。里面有一些非常不错的开源项目,分享出来供大家参考学习,...

    FunTester
  • 5分钟快速了解Docker的底层原理

    一位同学曾给我打比方:宿主机就好比一间大房子,docker把它成了N个小隔断。在这些小隔断之间,有独立的卫生间、小床、电视...

    xjjdog
  • 这个 Github 仓库因你而精彩

    我于今年 6 月份创建自己微信读者群。群组人数从一开始零星几人到现在的两百多号人。群里面的小伙伴都非常好学,经常来群里面讨论技术问题。我自己从中学到很多知识,也...

    猴哥yuri
  • 【GitHub 2017年度报告】70万中国新用户,Python超越Java成第二受欢迎语言

    【新智元导读】GitHub 2017年年度报告发布:这一年,全球200多个国家的2400万开发者用337种编程语言创建了2530万活跃repos。其中,有70万...

    新智元

扫码关注云+社区

领取腾讯云代金券