Linux学习笔记:
https://blog.csdn.net/2301_80220607/category_12805278.html?spm=1001.2014.3001.5482
前言:
前面两章我们已经讲了一些文件操作和文件重定向问题,以及一些相关的知识点,比如文件在内存中的存储位置,物理内存和虚拟内存的概念,文件描述符的问题等,今天我们要再学一个与内存有关的概念——用户缓冲区。
在操作系统中,缓冲区是用于存储数据的内存区域。在 Linux 中,用户缓冲区通常指的是由用户空间应用程序分配和管理的内存区域,用来存储从外部设备读取或写入的数据。操作系统通过缓冲区来避免频繁地进行 I/O 操作,提高效率,同时保证数据的完整性和一致性。
本篇主要通过一些代码示例来帮助大家理解缓冲区的问题,内容偏向于基础一点的,学习完之后可以结合一些Linux相关的书籍再看看
我们讲解的重点会放在讲解什么是缓冲区上,对于缓冲区存在的作用和种类等方面上了解一下就行
一、什么是缓冲区?
我们通过几个场景来揭露这个问题,首先我们先来看下面这串代码及其输出结果:
#include<stdio.h>
#include<string.h>
#include<unistd.h>
int main()
{ const char *fstr="hello fwrite\n";const char *str="hello write\n";//C语言接口printf("hello printf\n"); //stdout -> 1fprintf(stdout,"hello fprintf\n"); //stdout -> 1fwrite(fstr,strlen(fstr),1,stdout); //fread, stdout -> 1//操作系统提供的系统接口write(1,str,strlen(str)); return 0; }
运行结果:
我们可以把这个结果输出重定向到指定文件中去
./myfile>log.txt
cat log.txt
但是如果我们在代码段的最后一行加入fork函数来创建子进程,我们就会得到一个不一样的输出结果:
#include<stdio.h>
#include<string.h>
#include<unistd.h>
int main()
{ const char *fstr="hello fwrite\n";const char *str="hello write\n";//C语言接口printf("hello printf\n"); //stdout -> 1fprintf(stdout,"hello fprintf\n"); //stdout -> 1fwrite(fstr,strlen(fstr),1,stdout); //fread, stdout -> 1//操作系统提供的系统接口write(1,str,strlen(str)); fork(); return 0; }
运行结果:
我们发现再次输出重定向时结果发生了很大的改变,调用C语言接口的语句被打印了两遍,而系统调用接口则只被打印一遍,而且顺序也发生了变化,调用系统接口的先被打印
为什么会出现这种情况呢?在解释之前我们先来看下面这种情况:
#include<stdio.h>
#include<string.h>
#include<unistd.h>
int main()
{ const char *fstr="hello fwrite\n";//const char *str="hello write\n";//C语言接口printf("hello printf\n"); //stdout -> 1fprintf(stdout,"hello fprintf\n"); //stdout -> 1fwrite(fstr,strlen(fstr),1,stdout); //fread, stdout -> 1close(1);//操作系统提供的系统接口//write(1,str,strlen(str)); //fork(); return 0; }
我们只留下C语言的几个打印方式,同时在打印执行完后把1号文件关闭了
运行结果:
上面的每一条打印语句我们都通过\n来刷新缓冲区的,如果我们把\n去掉再执行一遍:
#include<stdio.h>
#include<string.h>
#include<unistd.h>
int main()
{ const char *fstr="hello fwrite";//const char *str="hello write\n";//C语言接口printf("hello printf"); //stdout -> 1fprintf(stdout,"hello fprintf"); //stdout -> 1fwrite(fstr,strlen(fstr),1,stdout); //fread, stdout -> 1close(1);//操作系统提供的系统接口//write(1,str,strlen(str)); //fork(); return 0; }
运行结果:
我们发现没有任何输出结果,这又是什么原因呢?
注意:是在close(1)关闭和\n去掉同时存在的情况下才有了这样的结果
但是如果我们是对系统接口执行这个操作:
执行结果:
我们发现此时有打印结果
其实原因如下:
我们对上面的内容做一个叙述:我们都知道我们写入的内容是要先存在缓冲区的,但实际上我们通过C语言的接口所写的内容,比如print、fprint等接口所写内容所存在的缓冲区并不是在内核中的,它是在内核以外的,是语言的这些接口随后调用write系统接口才将其写入内核中去的,在我们关闭1号显示器文件时,内核中写入的内容会被我们输出到显示其中,但是缓冲区中的内容我们需要先调用write接口写入内核中去,但是1号文件都被关闭了,所以自然 是不能再写入内核中去的,所以最后就不能被显示在显示器上