前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >60秒问答:请问下面的程序一共输出多少个"hello,world”

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

作者头像
程序员小王
发布2021-08-13 10:27:08
1.4K0
发布2021-08-13 10:27:08
举报
文章被收录于专栏:架构说架构说

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

例子1

代码语言:javascript
复制
#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

代码语言:javascript
复制
#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. 白银:小王的分析第二次,打印多少?不知道,必须分析多个个进程

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

相同颜色的是同一个进程

相同颜色的是同一个进程

代码语言:javascript
复制
[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同样会输出一个'-'。

相同颜色的是同一个进程

代码语言:javascript
复制
## 打印多少?
 
 ###  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; }

代码语言:javascript
复制

- 打印3个 hello

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

代码语言:javascript
复制
最少知识

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

  • 关于缓冲区,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操作流
本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2021-07-23,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Offer多多 微信公众号,前往查看

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

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

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 请问下面的程序一共输出多少个"hello,world”
    • 例子1
      • 例子2
        • 答案:傻傻分不清楚 例子1 8个,例子2 6个
          • 问题拆分:一共产生几个进程
            • 1. 青铜:小王的分析第一次,结果肯定是错误的
            • 2. 白银:小王的分析第二次,打印多少?不知道,必须分析多个个进程
          • 塔山
          领券
          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档