Linux内核源码学习之fork的缓冲区
2014-10-29 14:39
148 查看
由一道面试题引出比较好,之前写得太乱了
![](http://img.blog.csdn.net/20160404110946862)
会显示几个*?
答案是8个
![](http://img.blog.csdn.net/20160404111029722)
【更正】图中的一共输出"*"个数错了,应该是n*2^n个"*"。
后面是另一个例子和比较乱的讲解原因
不看也罢,两个问题。
1)fork父子进程执行顺序的不同导致输出结果的不同
![](http://img.blog.csdn.net/20141029143706389?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvYWdhbmxlbmd6aQ==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
上面的代码看上去很简单,子子孙孙fork就是了,基本上符合我们的一般的猜想,逻辑上很正正确,但是要说的是:
为什么同样的代码运行的时候得到的输出会有不同?
./fork执行完成之后很正常回到了shell,但是右边却没有回到shell,这是为什么呢?
这和fork的性质【fork之后并不能确定究竟是哪个进程首先执行】相关
左边的情况是:最后一个进程4742执行完之后,父进程还是没有结束的。然后父进程结束,回到父进程的父进程也就是shell
右边的情况是:在输出sjc@ubuntu等等之前父进程就已经执行结束退出了
所以后边的子进程执行结束后不会回到shell,而是会回到他的父进程,不知道是谁了,反正不会是shell,所以会造成图中所示的现象上面说的内容不是要说的重点内容,是个人理解,不一定对,欢迎指正!
2)缓冲区继承的问题
下面就来看看修改后的代码的执行情况,就和我们乍一看程序猜想或者理解上的不一致了。
![](http://img.blog.csdn.net/20141029143758484?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvYWdhbmxlbmd6aQ==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
同样的代码只是将打印语句的最后的'\n'换行符去掉了,运行效果确实差别很大:
打印出了16条语句!!!
这是为什么呢?看打印语句的内容:
其中第一条肯定是最初的进程打印的,这个不会有疑问,那么他的pid就是4772,可以看到,这个4772被打印了9次
剩下的7条分别是fork之后进程的进程pid
为什么会打印出9条?
原来这和fork的第二条性质是相关的【fork后子进程会复制父进程的资源,缓冲区是父进程的资源,所以自然会复制一份】
这样就好理解了,最初的进程有7个子孙进程,所以都复制一份一开始的缓冲区,到本身结束的时候exit会冲洗缓冲区,其中包括复制父进程的缓冲区和自己需要打印的自己的pid内容
最初的进程本身要打印两次(一开始和最后)所以就会打印2+7*2-=16条,其中4772打印2+7=9条
既然这样(子进程复制父进程的缓冲区),为什么之前打印语句中带有'\n'的实验就能够“正确”呢?
这是由【设备的不同缓冲属性】决定的。
我们现实运行结果的设备是标准输出设备,而【标准输出设备在正常情况下是linux中的行缓存的设备(除出错)】
'\n'正是换行符,所以会换行时清空缓存。
【linux中写入文件流是全缓存的,也就是换行符并不会冲洗缓冲区】我们让结果输出到文件中会是怎样的呢?
![](http://img.blog.csdn.net/20141029143805015?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvYWdhbmxlbmd6aQ==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
![](http://img.blog.csdn.net/20141029143726014?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvYWdhbmxlbmd6aQ==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
可以看到,不带'\n'的输出,除了没有了shell的提示符外,分析还是相同的
但是带有'\n'的输出到文件之后,变成了全缓冲的了,所以自然也会输出16条语句
想必经过这个实验,能对fork的特性和设备的特性有一个感性的认识了。。。。
会显示几个*?
答案是8个
【更正】图中的一共输出"*"个数错了,应该是n*2^n个"*"。
后面是另一个例子和比较乱的讲解原因
不看也罢,两个问题。
1)fork父子进程执行顺序的不同导致输出结果的不同
上面的代码看上去很简单,子子孙孙fork就是了,基本上符合我们的一般的猜想,逻辑上很正正确,但是要说的是:
为什么同样的代码运行的时候得到的输出会有不同?
./fork执行完成之后很正常回到了shell,但是右边却没有回到shell,这是为什么呢?
这和fork的性质【fork之后并不能确定究竟是哪个进程首先执行】相关
左边的情况是:最后一个进程4742执行完之后,父进程还是没有结束的。然后父进程结束,回到父进程的父进程也就是shell
右边的情况是:在输出sjc@ubuntu等等之前父进程就已经执行结束退出了
所以后边的子进程执行结束后不会回到shell,而是会回到他的父进程,不知道是谁了,反正不会是shell,所以会造成图中所示的现象上面说的内容不是要说的重点内容,是个人理解,不一定对,欢迎指正!
2)缓冲区继承的问题
下面就来看看修改后的代码的执行情况,就和我们乍一看程序猜想或者理解上的不一致了。
同样的代码只是将打印语句的最后的'\n'换行符去掉了,运行效果确实差别很大:
打印出了16条语句!!!
这是为什么呢?看打印语句的内容:
其中第一条肯定是最初的进程打印的,这个不会有疑问,那么他的pid就是4772,可以看到,这个4772被打印了9次
剩下的7条分别是fork之后进程的进程pid
为什么会打印出9条?
原来这和fork的第二条性质是相关的【fork后子进程会复制父进程的资源,缓冲区是父进程的资源,所以自然会复制一份】
这样就好理解了,最初的进程有7个子孙进程,所以都复制一份一开始的缓冲区,到本身结束的时候exit会冲洗缓冲区,其中包括复制父进程的缓冲区和自己需要打印的自己的pid内容
最初的进程本身要打印两次(一开始和最后)所以就会打印2+7*2-=16条,其中4772打印2+7=9条
既然这样(子进程复制父进程的缓冲区),为什么之前打印语句中带有'\n'的实验就能够“正确”呢?
这是由【设备的不同缓冲属性】决定的。
我们现实运行结果的设备是标准输出设备,而【标准输出设备在正常情况下是linux中的行缓存的设备(除出错)】
'\n'正是换行符,所以会换行时清空缓存。
【linux中写入文件流是全缓存的,也就是换行符并不会冲洗缓冲区】我们让结果输出到文件中会是怎样的呢?
可以看到,不带'\n'的输出,除了没有了shell的提示符外,分析还是相同的
但是带有'\n'的输出到文件之后,变成了全缓冲的了,所以自然也会输出16条语句
想必经过这个实验,能对fork的特性和设备的特性有一个感性的认识了。。。。
相关文章推荐
- Linux内核源码学习网页版
- Linux内核源码学习之僵尸进程
- 内核源码学习:套接字缓冲区提供的函数
- Linux内核源码学习之进程切换细节整理
- 【linux内核学习】怎么找到要修改的驱动源码
- Linux内核源码(asm/bitops/atomic.h)学习
- Linux内核学习笔记2——Linux内核源码结构
- Linux内核源码(asm/atomic.h)学习
- Linux内核设计与实现--学习笔记--第三章- 3(fork,vfork,clone)
- linux内核学习之网络篇——套接字缓冲区
- linux内核学习-3 fork()函数(关注新浪微博:寂寞侵蚀的岁月(4000多篇技术分享))
- Linux内核 fork 源码分析
- 使用 AppFuse 的七个理由--学习 Java 开放源码工具 —— 并使用这些工具提高生产效率
- 写给Linux内核新手-关于Linux内核学习的误区
- [收藏]JAVA源码学习网站(转)
- linux内核学习笔记——概述
- Struts 源码学习笔记
- 学习TerryLee 的设计模式:抽象工厂模式(附源码)_AX
- 很好的源码软件列表,有助于学习提高