一个fork的面试题
前两天有人问了个关于Unix的fork()系统调用的面试题,这个题正好是我大约十年前找工作时某公司问我的一个题,我觉得比较有趣,写篇文章与大家分享一下。这个题是这样的:
题目:请问下面的程序一共输出多少个“-”?
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | #include <stdio.h>#include <sys/types.h>#include <unistd.h>intmain(void){   inti;   for(i=0; i<2; i++){      fork();      printf("-");   }   wait(NULL);   wait(NULL);   return0;} | 
如果你对fork()的机制比较熟悉的话,这个题并不难,输出应该是6个“-”,但是,实际上这个程序会很tricky地输出8个“-”。
要讲清这个题,我们首先需要知道fork()系统调用的特性,
- fork()系统调用是Unix下以自身进程创建子进程的系统调用,一次调用,两次返回,如果返回是0,则是子进程,如果返回值>0,则是父进程(返回值是子进程的pid),这是众为周知的。
- 还有一个很重要的东西是,在fork()的调用处,整个父进程空间会原模原样地复制到子进程中,包括指令,变量值,程序调用栈,环境变量,缓冲区,等等。
所以,上面的那个程序为什么会输入8个“-”,这是因为printf(“-“);语句有buffer,所以,对于上述程序,printf(“-“);把“-”放到了缓存中,并没有真正的输出(参看《C语言的迷题》中的第一题),在fork的时候,缓存被复制到了子进程空间,所以,就多了两个,就成了8个,而不是6个。
另外,多说一下,我们知道,Unix下的设备有“块设备”和“字符设备”的概念,所谓块设备,就是以一块一块的数据存取的设备,字符设备是一次存取一个字符的设备。磁盘、内存都是块设备,字符设备如键盘和串口。块设备一般都有缓存,而字符设备一般都没有缓存。
对于上面的问题,我们如果修改一下上面的printf的那条语句为:
| 1 | printf("-\n"); | 
或是
| 1 2 | printf("-");fflush(stdout); | 
就没有问题了(就是6个“-”了),因为程序遇到“\n”,或是EOF,或是缓中区满,或是文件描述符关闭,或是主动flush,或是程序退出,就会把数据刷出缓冲区。需要注意的是,标准输出是行缓冲,所以遇到“\n”的时候会刷出缓冲区,但对于磁盘这个块设备来说,“\n”并不会引起缓冲区刷出的动作,那是全缓冲,你可以使用setvbuf来设置缓冲区大小,或是用fflush刷缓存。
我估计有些朋友可能对于fork()还不是很了解,那么我们把上面的程序改成下面这样:
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 | #include <stdio.h>#include <sys/types.h>#include <unistd.h>intmain(void){   inti;   for(i=0; i<2; i++){      fork();      //注意:下面的printf有“\n”      printf("ppid=%d, pid=%d, i=%d \n", getppid(), getpid(), i);   }   sleep(10); //让进程停留十秒,这样我们可以用pstree查看一下进程树   return0;} | 
于是,上面这段程序会输出下面的结果,(注:编译出的可执行的程序名为fork)
| 1 2 3 4 5 6 7 8 9 10 | ppid=8858, pid=8518, i=0ppid=8858, pid=8518, i=1ppid=8518, pid=8519, i=0ppid=8518, pid=8519, i=1ppid=8518, pid=8520, i=1ppid=8519, pid=8521, i=1$ pstree -p | grepfork|-bash(8858)-+-fork(8518)-+-fork(8519)---fork(8521)|            |            `-fork(8520) | 
面对这样的图你可能还是看不懂,没事,我好事做到底,画个图给你看看:

注意:上图中的我用了几个色彩,相同颜色的是同一个进程。于是,我们的pstree的图示就可以成为下面这个样子:(下图中的颜色与上图对应)

这样,对于printf(“-“);这个语句,我们就可以很清楚的知道,哪个子进程复制了父进程标准输出缓中区里的的内容,而导致了多次输出了。(如下图所示,就是我阴影并双边框了那两个子进程)

现在你明白了吧。(另,对于图中的我本人拙劣的配色,请见谅!)
(全文完)
转载自 酷壳
一个fork的面试题的更多相关文章
- 【转】 一个fork的面试题
		转自:一个fork的面试题 前两天有人问了个关于Unix的fork()系统调用的面试题,这个题正好是我大约十年前找工作时某公司问我的一个题,我觉得比较有趣,写篇文章与大家分享一下.这个题是这样的: 题 ... 
- [转帖]一个FORK的面试题
		一个FORK的面试题 https://coolshell.cn 搞不懂 fork 的含义. Linux 里面的线程不是教科书上面的标准的线程 好像用 父子进程来进行 模拟线程的处理 父子线程应该共享 ... 
- 一个fork的面试题——fork + 缓存区
		update : 20140512 题目:请问下面的程序一共输出多少个“-”? #include <stdio.h> #include <sys/types.h> #inclu ... 
- 一个FORK的面试题(转)
		https://coolshell.cn/articles/7965.html https://coolshell.cn/articles/945.html 
- 【APUE】一个fork的面试题及字符设备、块设备的区别
		具体内容见:http://coolshell.cn/articles/7965.html 字符设备.块设备主要区别是:在对字符设备发出读/写请求时,实际的硬件I/O一般就紧接着发生了,而块设备则不然, ... 
- golang学习笔记20 一道考察对并发多协程操作一个共享变量的面试题
		golang学习笔记20 一道考察对并发多协程操作一个共享变量的面试题 下面这个程序运行的能num结果是什么? package main import ( "fmt" " ... 
- 3个CCIE考官对一个高级工程师的面试题
		3个CCIE考官对一个高级工程师的面试题 转载 时间:2015-7-10 原文转载: 1.现在的6509及7609,SUP720交换带宽去到720G,是不是可以说7609/6509 可以取代一部分GS ... 
- 一个fork()系统调用的问题
		转载:http://coolshell.cn/articles/7965.html 题目:请问下面的程序一共输出多少个“-”? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 ... 
- 一个fork短码的扩展版本
		原本代码: 链接 int skip = !!fork() + 2*(!!fork()); for (uint32_t i=skip;i!=INT_MAX;i+=4) { } 这个是多进程加速循环的代码 ... 
随机推荐
- 【状态模式】 State Pattern
			我们先设计一个场景,饮料自动售卖机,来设计一下它的出售流程. 流程图中,我们可把这个过程看成几个状态: 投币状态,选择饮料状态,售出状态,出售完毕状态. ,有了这个四个状态,我们设计一下界面(很粗略) ... 
- 具有timeout 功能的函数调用
			做项目的时候有时经常会需要一个带有timeout功能的函数调用. 比如从后台读数据并期望在给定时间内返回.借此机会包装了一个简单的C# class, 直接上代码吧. public class Time ... 
- sql server 2008出现评估期已过的问题
			我的sql server2008用来半年吧,那天的昨天还能用,到了180天后,就不能用了,具体问题如下: 出了这个问题后,就打不开sql server了 解决方法: 1.打开安装中心,升级sql se ... 
- Access数据库的常用数据类型和alter的用法
			一.Access比较常用的数据类型:文本.备注.数字.日期/时间.货币 意思 Sql Access 1)文本 nvarchar(30) ... 
- linux下安装或升级GCC4.8,以支持C++11标准
			C++11标准在2011年8月份获得一致通过,这是自1998年后C++语言第一次大修订,对C++语言进行了改进和扩充.随后各编译器厂商都各自实现或部分实现了C++中的特性. 如需查看各编译器对C++1 ... 
- DP入门---Robberies
			HDU 2955 Description The aspiring Roy the Robber has seen a lot of American movies, and knows that ... 
- maven-dependency-plugin插件的使用
			maven-dependency-plugin插件的使用 maven-dependency-plugin是 处理与依赖相关的插件.它有很多可用的goal,大部分是和依赖构建.分析和解决相关的goa ... 
- SharpGL学习笔记(十八) 解析3ds模型并显示
			笔者设想的3D仿真中的元件,是不可能都是“画”出来的.这样就玩复杂了,应该把任务分包出去,让善于制作模型的软件来制作三维模型,我们只需要解析并且显示它即可. 3dsmax制作三维模型的方便,快捷,专业 ... 
- 使用Apache ab进行压力测试(参数说明)
			我们一般会使用Apache自带的ab来对项目进行压力测试,看项目的执行情况如何. 我们可以使用 ab -v 来查看ab的详细参数使用方法. [root@node234 bin]# ./ab -v ab ... 
- Vue中class与style绑定
			gitHub地址:https://github.com/lily1010/vue_learn/tree/master/lesson07 一 用对象的方法绑定class 很简单,举个栗子: <!D ... 
