计算机系统之深入理解fork()函数(面试题) 您所在的位置:网站首页 fork函数的规则 计算机系统之深入理解fork()函数(面试题)

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

2024-01-01 15:15| 来源: 网络整理| 查看: 265

最近在深入理解计算机系统(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个线程。



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有