专栏首页架构说60秒问答:请问下面的程序一共输出多少个"hello,world”

60秒问答:请问下面的程序一共输出多少个"hello,world”

请问下面的程序一共输出多少个"hello,world”

例子1

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

int main(void)
{
    int i;
    for (i = 0; i < 2; i++) {
        fork();
        printf("?"); //hello,world
    }
    return 0;
}

例子2

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

int main(void)
{
    int i;
    for (i = 0; i < 2; i++) {
        fork();
        printf("?\n");//hello,world
    }
    return 0;
}

答案:傻傻分不清楚 例子1 8个,例子2 6个

问题拆分:一共产生几个进程

1. 青铜:小王的分析第一次,结果肯定是错误的

循环里有fork ,fork 里面有循环 结果是死循环 ,造成stack溢出呀,根本不会输出 在哪里思维停顿了。

点评:

  1. 虽然看很多次,对fork原理还是不懂,
  2. 之前对:线程,协程 切换概念感觉很了解,stack存储局部遍历,寄存器
  3. 之前对gdb, 白学习了,stack存储局部遍历,你这个却理解不了

补充最少知识

  • fork的实现

fork的实现分为以下两步

  1. 复制进程资源
  2. 执行该进程

复制进程的资源包括以下几步

  1. 进程pcb
  2. 程序体,即代码段数据段等
  3. 用户栈
  4. 内核栈
  5. 虚拟内存池
  6. 页表

fork()系统调用的特性

  • fork()系统调用是Unix下以自身进程创建子进程的系统调用,一次调用,两次返回,如果返回是0,则是子进程,如果返回值>0,则是父进程(返回值是子进程的pid),这是众为周知的。【青铜:都知道】
  • 还有一个很重要的东西是,在fork()的调用处,整个父进程空间会原模原样地复制到子进程中,包括指令,变量值,程序调用栈,环境变量,缓冲区,等等。【白银:别人知道我不知道】

2. 白银:小王的分析第二次,打印多少?不知道,必须分析多个个进程

你现在任务分析多少个进程,不考虑打印多少?

相同颜色的是同一个进程

相同颜色的是同一个进程

[misaki@localhost test]$ ./main
ppid:2221, pid:4846
ppid:4846, pid:4847
ppid:2221, pid:4846
ppid:4846, pid:4848
ppid:4846, pid:4847
ppid:4847, pid:4849


[misaki@localhost ~]$ pstree -ap misaki
sshd,2220
  ├─bash,2221
  │   └─main,4846(P1)
  │       ├─main,4847(P2)
  │       │   └─main,4849 P(3)
  │       └─main,4848(P4)
  └─bash,3571
      └─pstree,4850 -ap misaki
  • p1 进程 首先程序一开始,bash产生一个进程P1执行此程序,P1进入程序。
  • P2进程 当i=0时:fork()产生一个子进程P2,同时它自己输出一个'-'。P2继承P1的诸如环境变量,P2首现会输出一个'-'。

当i=1,会继续执行for循环---P2先fork()出一个子进程P3,同时再输出一个'-'。

  • P3进程 P3进程为P2的子进程,它会复制其父进程P2的指令,变量值,程序调用栈,环境变量,缓冲区等,它会输出一个'-'。
  • P4 此时P1进入程序后,当i=1时,fork()产生另一个它的子进程P4,同时输出一个'-'。P4同样会输出一个'-'。

相同颜色的是同一个进程

## 打印多少?
 
 ###  1. 青铜:小王的分析第一次,结果肯定是错误的 
 
  > 被多个fork 吓住了,却没想到 块设备 和字符设备的区别?
  
  点评:cout flush函数都不懂,差
 
 

- 打印4个 hello

#include <stdio.h> #include <unistd.h> #includeusing namespace std; int main(void) { cout<< "hello" ; fork(); cout<< "hello" ; return 0; }

- 打印3个 hello

#include <stdio.h> #include <unistd.h> #includeusing namespace std; int main(void) { cout<< "hello" << endl; fork(); cout<< "hello" << endl; return 0; }

最少知识

我们的子进程会复制父进程的缓冲区。

  • 关于缓冲区,Unix下的设备块设备和字符设备的概念, 所谓块设备,就是以一块一块的数据存取的设备,字符设备是一次存取一个字符的设备。磁盘、内存都是块设备,字符设备如键盘和串口。块设备一般都有缓存,而字符设备一般都没有缓存。

程序遇到“\n”,或是EOF,或是缓冲区满,或是文件描述符关闭,或是主动flush,或是程序退出,就会把数据刷出缓冲区。

  • 需要注意的是,标准输出是行缓冲,所以遇到“\n”的时候会刷出缓冲区, 但对于磁盘这个块设备来说,“\n”并不会引起缓冲区刷出的动作,那是全缓冲,你可以使用setvbuf来设置缓冲区大小,或是用fflush刷缓存。
  • 块设备通过系统缓存进行读取,不是直接和物理磁盘读取。字符设备可以直接物理磁盘读取,不经过系统缓存。(如键盘,直接相应中断) 这是因为printf(“-”);语句有buffer,所以,对于上述程序,printf(“-”);把“-”放到了缓存中,
  • 在fork的时候,缓存被复制到了子进程空间,所以,就多了两个,就成了8个,而不是6个。
    • 因为P4为P1的一个子进程它会继承P1的缓冲区,其中有一个'-',所以P4会输出两个'-'.
    • 因为这里P3会继承P2的缓冲区,其中有一个'-',所以P3会输出两个'-'.
    • 3. 黄金:小王的分析第三次,流程图必须清楚 ,别头疼

塔山

  • linux 进程 fork() https://zhuanlan.zhihu.com/p/53527981
  • fork与printf的缓存问题
  • fork创建子进程(printf的打印次数问题)
  • 一个关于fork()的面试题
  • https://blog.csdn.net/yao5hed/article/details/81273677
  • fork()的底层实现机制 https://blog.csdn.net/dianacody/article/details/22401475
  • fork()函数的面试题
  • C++之标准设备IO操作流

本文分享自微信公众号 - 架构说(JiaGouS),作者:王传义

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

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

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

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 程序员必备的16个实用的网站

    3个月以前在知乎上回答一个问题【有哪些能集实用,装逼于一身的冷门网站?】得到很多小伙伴的喜爱,一直到现在都还陆陆续续收到大家的赞,谢谢大家。

    Java后端技术
  • 盛弘电气2021秋招笔试题

    答案:如果在实际的调试过程中,怀疑某处发生了内存泄露,可以查看该进程的maps表,看进程的堆段或者mmap段的虚拟地址空间是否持续增加,如果是,说明很可能发生了...

    Jasonangel
  • Python 练习100题---No.(1-20)---附其他题目解答链接

    github展示python100题 链接如下: https://github.com/zhiwehu/Python-programming-exercises...

    用户7886150
  • 关于JavaScript计时器的知识学习

    推特上大约一半的回答都是错误的。答案并不是 V8(或者虚拟机)!!虽然“JavaScript”计时器” 很出名,但是 setTimeout 和 setInter...

    coder_koala
  • 【ZMQ】第一个C服务器

    ØMQ (也拼写作ZeroMQ,0MQ或ZMQ),号称号称是“史上最快的消息队列”,基于c语言开发。ZMQ(以下ZeroMQ简称ZMQ)是一个简单好用的传输层,...

    宋天伦
  • OpenResty学习指南(一)

    我的博客: https://www.luozhiyun.com/archives/217

    luozhiyun
  • C语言嵌入式系统编程修炼之屏幕操作

    这是我13年前创作和发表在互联网上的文章,这么多年过去了,这篇文章仍然在到处传播。现在贴回Linuxer公众号。 全文目录: C语言嵌入式系统编程修炼之道——背...

    企鹅号小编
  • 50 种不同编程语言的“Hello World”,你知道多少?

    历经 70 年,不断出现的编程语言为开发者解决了哪些难题?其存在又有怎样的特性?本文将以「Hello World」为例,花样呈现 50 种编程语言。

    杰哥的IT之旅
  • 编程语言发展70年,用50种不同语言输出「Hello World」

    【导读】历经 70 年,不断出现的编程语言为开发者解决了哪些难题?其存在又有怎样的特性?本文将以「Hello World」为例,花样呈现 50 种编程语言。

    AI科技大本营
  • 【译】教你用50种语言写Hello, World

    甚至有一个名为TTHW的指标来衡量一个程序员接触一门新的编程语言时,成功写出“Hello, World!“并运行所需要的时间。

    Jackeyzhe
  • 50种不同编程语言的“Hello, World”,你会写几种?

    当我们学习一门编程语言时,都是从“Hello, World!”开始。所有程序员在其职业生涯中,都至少接触过一个经典的“Hello, World!” 程序。通常程...

    华章科技
  • .net异步性能测试(包括ASP.NET MVC WebAPI异步方法)

    很久没有写博客了,今年做的产品公司这两天刚刚开了发布会,稍微清闲下来,想想我们做的产品还有没有性能优化空间,于是想到了.Net的异步可以优化性能,但到底能够提升...

    用户1177503
  • 近 50 种花式 “Hello, World”

    当我们学习一门编程语言时,都是从“Hello, World!”开始。所有程序员在其职业生涯中,都至少接触过一个经典的“Hello, World!” 程序。通常程...

    猿哥
  • StackOverflow上高赞问题:为什么处理一个排序数组要比非排序数组快的多

    今天,我们一起看几个 StackOverflow 上关于 Java 的几个高赞答案。

    业余草
  • Python-定时器使用

    通过crontab -e命令,添加定时器任务。定期执行python的脚本。如果-e后面是多条命名,可以用分号”;”进行分割。用分号 (;) 所分割的话,那么命令...

    py3study
  • python asyncio异步http(并行编程 30)

    前言:python由于GIL(全局锁)的存在,不能发挥多核的优势,其性能一直饱受诟病。然而在IO密集型的网络编程里,异步处理比同步处理能提升成百上千倍的效率,弥...

    用户5760343
  • C语言C加加编程新手基础入门,学习之嵌入式系统编程,修炼之屏幕操作

    全文目录: C语言嵌入式系统编程修炼之道——背景篇 C语言嵌入式系统编程修炼之道——软件架构篇 1.模块划分 2.多任务还是单任务 3.单任务程序典型架构 4....

    企鹅号小编
  • StackOverflow 上面最流行的 7 个 Java 问题!

    StackOverflow发展到目前,已经成为了全球开发者的金矿。它能够帮助我们找到在各个领域遇到的问题的最有用的解决方案,同时我们也会从中学习到很多新的东西。

    路人甲Java
  • StackOverflow 上面最流行的 7 个 Java 问题!

    StackOverflow发展到目前,已经成为了全球开发者的金矿。它能够帮助我们找到在各个领域遇到的问题的最有用的解决方案,同时我们也会从中学习到很多新的东西。

    良月柒

扫码关注云+社区

领取腾讯云代金券