文章目录
- 什么是缓冲区?
- 为什么要有缓冲区?
- 缓冲区刷新策略
- 请看下面代码:
接着上篇【Linux】文件操作|文件描述符|重定向
什么是缓冲区?
我们口中说的缓冲区,一般指的是用户级语言层面给我们提供的缓冲区。本质就是一段内存。
具体在C语言文件操作的中FILE结构体中。它内部不仅有文件描述符fd还有缓冲区。
为什么要有缓冲区?
比如我们从磁盘里取信息,我们先把读出的数据放在缓冲区,计算机再直接从缓冲区中取数据,等缓冲区的数据取完后再去磁盘中读取,这样就可以减少磁盘的读写次数,再加上计算机对缓冲区的操作大大快于对磁盘的操作,故应用缓冲区可大大提高计算机的运行速度。
缓冲区就是一块内存区,它用在输入输出设备和CPU之间,用来缓存数据。它使得低速的输入输出设备和高速的CPU能够协调工作,避免低速的输入输出设备占用CPU,解放出CPU,使其能够高效率工作。
缓冲区刷新策略
缓冲区会结合具体的设备,制定适合自己的刷新策略。
1.立即刷新,无缓冲。
2.行刷新,行缓冲。
一般是在显示器上,因为要适应我们人类的阅读习惯。从左到右。一次阅读。 而不是一次刷新一大片。这样不方便阅读。
3.缓冲区已经满了,这时就要全缓冲。
一般对应的是磁盘文件。
其他情况:
1.用户强制刷新。
2.进程退出时要进行缓冲区刷新。
请看下面代码:
#include <stdio.h>
#include <string.h>
#include <unistd.h>
int main()
{
// C接口
printf("hello printf\n");
fprintf(stdout, "hello fprintf\n");
const char *fputsString = "hello fputs\n";
fputs(fputsString, stdout);
// 系统接口
const char *wstring = "hello write\n";
write(1, wstring, strlen(wstring));
fork(); // fork
return 0;
}
运行结果:
解释:
代码结束之前,进行创建子进程
- 如果我们没有进行重定向
>
,看到了4条消息,stdout 默认使用的是行刷新,在进程fork之前,三条C语言函数已经将数据进行打印输出到显示器上(外设),FILE内部的缓冲区中已经不存在对应的数据了。 - 如果我们进行了重定向
>
, 写入的文件不再是显示器stdout,而是普通文件,采用的刷新策略是全缓冲,之前的3条c语言函数虽然带了\n,但不足以将普通文件的缓冲区写满!数据并没有被刷新,就是现在缓冲区里还存在未被刷新的数据。
执行fork创建子进程之后, 子进程把缓冲区的整体复制了一份,然后紧接着就是return 0
进程退出!谁先退出,一定要进行缓冲区刷新,那么这时候缓冲区就要被修改了,OS为了保证进程独立性,就要进行写时拷贝,所以数据最终会显示两份。 - write为什么没有打印两次呢?上面的过程都和wirte无关,wirte是系统调用,没有结构体指针FILE,用的是fd,就没有C提供的缓冲区,就不存在缓冲区被修改的问题。