Linux内核源码学习之fork的缓冲区

上面的代码看上去很简单,子子孙孙fork就是了,基本上符合我们的一般的猜想,逻辑上很正正确,但是要说的是:

为什么同样的代码运行的时候得到的输出会有不同?

./fork执行完成之后很正常回到了shell,但是右边却没有回到shell,这是为什么呢?

这和fork的性质【fork之后并不能确定究竟是哪个进程首先执行相关】

左边的情况是:最后一个进程4742执行完之后,父进程还是没有结束的。然后父进程结束,回到父进程的父进程也就是shell

右边的情况是:在输出[email protected]等等之前父进程就已经执行结束退出了

所以后边的子进程执行结束后不会回到shell,而是会回到他的父进程,不知道是谁了,反正不会是shell,所以会造成图中所示的现象上面说的内容不是要说的重点内容,是个人理解,不一定对,欢迎指正!

下面就来看看修改后的代码的执行情况,就和我们乍一看程序猜想或者理解上的不一致了。

同样的代码只是将打印语句的最后的‘\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的特性和设备的特性有一个感性的认识了。。。。

时间: 2024-07-28 20:47:20

Linux内核源码学习之fork的缓冲区的相关文章

Linux内核源码学习之 数据结构

本篇记录在学习Linux内核源码过程中对一些知道但不熟悉不会用的数据结构进行记录. union 是在学习进程复制函数do_fork中遇到的: <sched.h> union thread_union { struct thread_info thread_info; unsigned long stack[THREAD_SIZE/sizeof(long)]; }; struct  thread_info和stack被声明为union 共享空间 "联合"是一种特殊的类,也是一

Linux内核源码学习之 内核页表打印

本学期Linux内核实验最后是打印内核页表,线性地址----物理地址 我看到这个实验题目的时候想到的就是这个init函数(因为这部分当时就是我讲的^_^),这个函数是初始化linux内核页表的,也就是将32位系统中3G以上的896M线性地址映射到物理地址的0-896M,在其调用者paging_init函数中还处理了其他的情况,比如固定映射之类的.那属于高端内存映射那一块的内容,目前我们先看一下如何将内核页表3G~3G+896M的线性地址对应的物理地址打印出来. 一下的源码是linux2.6.11

Linux内核源码学习之进程切换细节整理

linux中的进程是个最基本的概念,进程从运行队列到开始运行有两个开始的地方, 一个就是switch_to宏中的标号1:"1:/t",//只要不是新创建的进程,几乎都是从上面的那个标号1开始的,而switch_to宏则是除了内核本身,所有的进程要 想运行都要经过的地方 另 一个就是ret_form_fork 这样看来,虽然linux的进程体系以及进程调度非常复杂,但是总体看来就是一个沙漏状, 对于系统中的每个新进程它首次被执行的过程必然是: sys_fork---->do_for

Linux内核源码学习之 基本知识

GNOME GNOME是一种让使用者容易操作和设定电脑环境的工具,GNOME 包含了 Panel (用来启动此程式和显示目前的状态).桌面(应用程式和资料放置的地方).及一系列的标准桌面工具和应用程式,并且能让各个应用程式都能正常地运作.不管之前使用何种操作系统,都能轻易地使用 GNOME 功能强大的图形接口工具. KDE KDE,K桌面环境(KoolDesktop Environment)的缩写.一种著名的运行于 Linux.Unix 以及FreeBSD 等操作系统上面自由图形工作环境,整个系

Linux内核源码学习之僵尸进程

孤儿进程和僵尸进程 正常的子进程fork其父进程后,二者建立父子关系. 当子进程终结时,它会通知父进程,并清空自己所占据的内存,并在kernel里留下自己的退出信息(exit code,如果顺利运行,为0:如果有错误或异常状况,为>0的整数).在这个信息里,会解释该进程为什么退出.父进程在得知子进程终结时,有责任对该子进程使用wait系统调用.这个wait函数能从kernel中取出子进程的退出信息,并清空该信息在kernel中所占据的空间.这是正常的一般情况. 如果父进程早于子进程终结,子进程就

轻松学习linux内核源码的方法

轻松学习Linux操作系统内核源码的方法 针对好多Linux 爱好者对内核很有兴趣却无从下口,本文旨在介绍一种解读linux内核源码的入门方法,而不是解说linux复杂的内核机制:一.核心源程序的文件组织:1.Linux核心源程序通常都安装在/usr/src/linux下,而且它有一个非常简单的编号约定:任何偶数的核心(例如2.0.30)都是一个稳定地发行的核心,而任何奇数的核心(例如2.1.42)都是一个开发中的核心. 本文基于稳定的2.2.5源代码,第二部分的实现平台为 RedHat Lin

Linux内核源码分析方法

  一.内核源码之我见 Linux内核代码的庞大令不少人“望而生畏”,也正因为如此,使得人们对Linux的了解仅处于泛泛的层次.如果想透析Linux,深入操作系统的本质,阅读内核源码是最有效的途径.我们都知道,想成为优秀的程序员,需要大量的实践和代码的编写.编程固然重要,但是往往只编程的人很容易把自己局限在自己的知识领域内.如果要扩展自己知识的广度,我们需要多接触其他人编写的代码,尤其是水平比我们更高的人编写的代码.通过这种途径,我们可以跳出自己知识圈的束缚,进入他人的知识圈,了解更多甚至我们一

linux内核源码注解

轻松学习Linux操作系统内核源码的方法 针对好多Linux 爱好者对内核很有兴趣却无从下口,本文旨在介绍一种解读linux内核源码的入门方法,而不是解说linux复杂的内核机制:一.核心源程序的文件组织:1.Linux核心源程序通常都安装在/usr/src/linux下,而且它有一个非常简单的编号约定:任何偶数的核心(例如2.0.30)都是一个稳定地发行的核心,而任何奇数的核心(例如2.1.42)都是一个开发中的核心. 本文基于稳定的2.2.5源代码,第二部分的实现平台为 RedHat Lin

Linux内核源码分析--内核启动之(5)Image内核启动(rest_init函数)(Linux-3.0 ARMv7)【转】

原文地址:Linux内核源码分析--内核启动之(5)Image内核启动(rest_init函数)(Linux-3.0 ARMv7) 作者:tekkamanninja 转自:http://blog.chinaunix.net/uid-25909619-id-4938395.html 前面粗略分析start_kernel函数,此函数中基本上是对内存管理和各子系统的数据结构初始化.在内核初始化函数start_kernel执行到最后,就是调用rest_init函数,这个函数的主要使命就是创建并启动内核线