两道有趣的fork面试题

同学参加了EMC的笔试回来,说了一个EMC的一个笔试题目,他没有答上来,就问我。我感觉很有意思,就拿出来分析一下

intmain(intargc,char*argv[])

{

fork();

fork()&&fork()||fork();

fork();

}

为了解答这个问题,我们先作一下弊,先用程序验证一下,到此有多少个进程。

intmain(intargc,char*argv[])

{

fork();

fork()&&fork()||fork();

fork();

printf(

}

在代码最后加一个printf语句,看最后有多少行,就说明有多少进程。答案是总共20个进程,出去main进程,还有19个进程。

我们再来仔细分析一下,为什么是还有19个进程。

第一个fork和最后一个fork肯定是会执行的。主要在中间3个fork上,可以画一个图进行描述。这里就需要注意&&和||运算符。

A&&B,如果A=0,就没有必要继续执行了;A非0,就需要继续执行&&B。A||B,如果A非0,就没有必要继续执行了,A=0,就需要继续执行||B。

fork()对于父进程和子进程的返回值是不同的,按照上面的A&&B和A||B的分支进行画图,可以得出5个分支。

加上前面的fork和最后的fork,所有的进程都会执行,会产生4个分支,总共4*5=20个分支,也就是20个进程,除去main主进程,就是19个进程了。前两天有人问了个关于Unix的fork()系统调用的面试题,这个题正好是我大约十年前找工作时某公司问我的一个题,我觉得比较有趣,写篇文章与大家分享一下。这个题是这样的:

#include

#include

#include

intmain(void)

{

inti;

for(i=0;i

fork();

printf(

}

return0;

}

如果你对fork()的机制比较熟悉的话,这个题并不难,输出应该是6个“-”,但是,实际上这个程序会很tricky地输出8个“-”。

要讲清这个题,我们首先需要知道fork()系统调用的特性,•

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

或者是

printf(

flush();

就没有问题了,因为程序遇到“\n”或是EOF,或是缓中区满,或是文件描述符关闭,或是主动flush,就会把数据刷出缓冲区。

我估计有些朋友可能对于fork()还不是很了解,那么我们把上面的程序改成下面这样:

#include

#include

#include

intmain(void)

{

inti;

for(i=0;i

fork();

//注意:下面的printf有“\n”

printf(

}

sleep(10);//让进程停留十秒,这样我们可以用pstree查看一下进程树return0;

}

于是,上面这段程序会输出下面的结果,(注:编译出的可执行的程序名为fork)

ppid=8858,

ppid=8858,

ppid=8518,

ppid=8518,

ppid=8518,

ppid=8519,pid=8518,pid=8518,pid=8519,pid=8519,pid=8520,pid=8521,i=0i=1i=0i=1i=1i=1

$pstree-p|grepfork

|-bash(8858)-+-fork(8518)-+-fork(8519)---fork(8521)

||`-fork(8520)

面对这样的图你可能还是看不懂,没事,我好事做到底,画个图给你看看:注意:上图中的我用了几个色彩,相同颜色的是同一个进程。于是,我们的pstree

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

现在你明白了吧。


© 2024 实用范文网 | 联系我们: webmaster# 6400.net.cn