计算机系统之深入理解fork()函数(面试题)

最近在深入理解计算机系统(CSAPP)这门课上学到了异常控制流(Exception Control Flow)这一章节,其中书上关于fork()有许多理解。
我们今天就先来做一道面试题目理解理解fork()函数具体的含义。

1.第一题题目描述

在这里插入图片描述
请问上图会输出几次Hello?

根据下面的手绘图,我们可以看到总共有6个printf,于是我们不难猜到答案是6个Hello。

在这里插入图片描述
所以直接把代码在Ubuntu运行一下试试。
在这里插入图片描述
我们可以看到的确是6个Hello,而到这里的话,第一题也已经讲完啦。

2.第二题题目描述

在这里插入图片描述
请问上图会输出几次Hello?
看到这里,可能会有小伙伴有疑问了,会翻到上面去看这题和上题难道有什么不同吗?
细心的小伙伴发现这道题目把 Hello 后面的 \n 给去掉了。
\n 在c语言里面不就是换行的意思吗?
所以答案应该还是6个Hello。
我们依旧在Ubuntu里面实验一下。
重新编译后再次运行。

在这里插入图片描述

我们可以发现系统输出了8个Hello。
原因是
在fork()的调用处,整个父进程空间会原模原样地复制到子进程中,包括指令,变量值,环境变量,缓冲区,等等。
而printf语句其实并不会马上把结果输出到屏幕上,而是先到缓存区里面,在进行缓存区输出到屏幕。
\n 其实不仅仅代表着换行的意思,还包括清空缓存区。我们在调用fork()时,缓存区也被复制到子进程。
所以在最后,由原本的父进程输出2次,子进程输出2次。变成了父进程输出4次,子进程输出8次。

最后我们还可以验证一下我们的结论,一般fflush(stdout)是用来刷新缓存,我们把它加进程序,重新编译看看效果。
在这里插入图片描述

在这里插入图片描述
我们可以看到最后只输出了6个Hello。

3.第三题题目描述

在这里插入图片描述
在这里插入图片描述
我们可以看到运行出来的结果是 Linux Hello
那么,有什么办法改一下if中的条件让输出顺序换一下,换成Hello Linux吗?

做这题我们要知道fork函数有两个返回值,fork()的作用是产生一个子进程。
如果调用成功则返回两个值,子进程返回0,父进程返回子进程ID;否则,出错返回-1。
上图就是因为父进程快于子进程运行,所以先输出Linux,再输出Hello。

所以我们的改动是加上一个wait()函数。
wait函数的作用是会暂停当前进程,直到子进程结束。
进程一旦调用了wait,就会马上阻塞自己,由wait()自动分析当前进程的某个子进程是否已经退出,如果它找到了这样一个已经变成僵尸进程的子进程,wait()收集此子进程信息后销毁且返回。
所以,在fork()之后加上wait()进行判断,此时主进程由fork()返回子进程ID(非0)并被wait()强制暂停;子进程由fork()创造并返回0,打印Hello随后被销毁。

我们就可以直接看代码和结果了。系统输出的是HelloLinux。
在这里插入图片描述
在这里插入图片描述

4.第四题题目描述

int main(int argc, char* argv[])
{
   fork();
   fork() && fork() || fork();
   fork();
}

请问总共创建了多少个进程?

这个题目要解出来主要看第4行代码。
第3行和第5行都是只有一个fork(),所以会产生4个分支,剩下的就是看如何解析第4行了。
当 A && B,如果A = 0,则不继续执行 && B。如果A≠0,则继续执行 && B。
当 A || B,如果 A ≠ 0,则不继续执行 , 如果A = 0,则继续执行 || B。

假设当我们仅执行第4行代码时,手绘图如下:
在这里插入图片描述
我们可以看到总共有5个分支。

前面算出2个fork()是4个分支,所以4×5 = 20,总共有20个分支,去掉main主线程。
我们就可以得到答案是创建了19个线程。

  • 2
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值