波奇学Linux:文件缓冲区

问题导入

文件流输出直接向显示器和重定向文件有不一样的表现

分别向显示器文件输出四个语句,最后fork创建子进程。

波奇学Linux:文件缓冲区_第1张图片

当程序运行时和程序重定向到文件中,输出的内容不一样。

重定向时c库函数(printf,fprintf,fwrite)调用了两次,而系统调用write函数只调用了一次

波奇学Linux:文件缓冲区_第2张图片

关闭对应的虚拟文件,只有系统调用可以输出

屏蔽系统调用,同时关闭显示器对应的虚拟文件

波奇学Linux:文件缓冲区_第3张图片

运行程序没有任何输出,只有系统调用有输出。如果先close(1)再系统调用也没有任何输出。

波奇学Linux:文件缓冲区_第4张图片

解释问题

问题二的解释

调用c的库函数是存在一个用户级别的缓冲区,当缓冲区的数据刷新时会把数据刷新到内核级别的缓冲区,而write函数可以直接把数据输入内核级别的缓冲区,而close的作用关闭fd为1虚拟文件。

相当于fprintf/printf和fwrite刷新不到内核级别的缓冲区了,而write可以直接写入。所以只有write的输出有结果。

波奇学Linux:文件缓冲区_第5张图片

那么就是说,只要把数据刷新到内核级别的缓冲区就能输入到显示器中。

目前我们认为,只要将数据刷新到内核,数据就可以刷新到硬件

用户级别缓冲区的刷新策略

无缓冲---直接刷新

行缓冲---缓冲区不刷新,直到碰到\n ---显示器

全缓冲---缓冲区写满才刷新---普通文件写入

进程退出也会刷新

显示器的文件的刷新方案是行刷新,所以printf执行完就立即遇到\n

因此我们只要加上\n让缓冲区立刻刷新,保证在close代码前就把数据刷新进入内核中,就能把信息输出到屏幕上。

波奇学Linux:文件缓冲区_第6张图片

所以在原代码中,库函数调用的语句都在缓冲区,没有立刻刷新,当进程退出时刷新缓冲区时,已经运行了close语句,此时缓冲区已经没办法找到内核了。

刷新的本质就是将数据通过fd=1+write接口写入到内核中.

有了以上铺垫我们就可以解释为什么库函数调用exit会刷新缓冲区,系统调用_exit不会刷新缓冲区

对于exit而言,他是包含用户级别的缓冲区而内核的,而_exit只知道内核,无法接触上一级的缓冲区也就无法刷新。

解释问题一

重定向意味着文件流是输入到普通文件,而不是显示器,是全缓冲策略。\n不会再刷新缓冲区,而是进程结束时刷新缓冲区。

而进程前运行fork函数,对数据进行写时拷贝。产生两个缓冲区。

波奇学Linux:文件缓冲区_第7张图片

注意write的输入不经过这个缓冲区,所以不会重复。

以fprintf举例。

波奇学Linux:文件缓冲区_第8张图片

缓冲区存在意义

体现封装的特性,对于库函数来说,不需要关注数据是如何刷新到硬件上的,只用把数据刷新到缓冲区即可

配合格式化,如将int型等都转换为字符串

你可能感兴趣的:(linux,运维,服务器)