【Linux】缓冲区与缓冲区的刷新策略


目录

1.缓冲区基础

1.1缓冲区的刷新策略

1.1.1三种刷新策略

1.1.2.两种强制刷新策略

2.用户级语言层缓冲区

2.1.默认在显示器输出

2.2.重定向到文件输出

2.3.write调用没有显示两份的原因

3.模拟实现文件缓冲区

3.1 myFileBuffer.h

3.2 myFileBuffer.c

4.系统内核缓冲区

最后


1.缓冲区基础

缓冲区本身就是一段内存,就是用来执行做缓存的一段内存空间。

内存对磁盘进行存储信息,称为外设IO,速度很慢

缓冲区是,直接在内存中开辟一段空间,将数据拷贝在缓存区中,在缓存区的数据会定期刷新给磁盘,有效的节省了进程进行数据IO的时间。

1.1缓冲区的刷新策略

缓冲区会结合具体的设备执行自己的刷新策略。

1.1.1三种刷新策略

1.立即刷新  无缓冲

2.行刷新      行缓冲 显示器(显示器设备特殊符合人类的阅读习惯,按行缓存提升效率不至于太低

3.缓冲区刷新  全缓冲  磁盘文件  (效率最高,定期一次刷新出去

1.1.2.两种强制刷新策略

1.用户强制刷新 fflush()

2.进程退出 ,一般都要进行缓冲区刷新


2.用户级语言层缓冲区

这个缓冲区在C语言提供的FILE结构体中

测试代码:

  1 #include<stdio.h>2 #include<unistd.h>3 #include<string.h>4 5 int main()6 {7   printf("hello printf\n");8   fprintf(stdout,"hello fprintf\n");9   const char* fputsString="hello fputs\n";10   fputs(fputsString,stdout);11 12   //系统接口13   const char*  writeString="hello write\n";                  14   write(1,writeString,strlen(writeString));15                                            16   fork();17          18   return 0;19 }          20  

在显示器上输出

重定向到文件输出

两种输出方式结果不同,其中重定向到文件输出的内容,比直接到显示器输出的内容c语言的接口多输出了一遍,是因为文件和显示器的缓冲区刷新策略不同。

在代码结束之前,先创建了子进程

2.1.默认在显示器输出

显示器的刷新策略是行缓冲刷新,在进程fork之前,三条c语言的内容已经被行刷新到显示器上。在fork后其FILE内部已经不存在对应的数据。

2.2.重定向到文件输出

文件的刷新策略是全缓冲,之前的显示函数虽然带了\n,但是不足以把文件的缓冲区写满,此时数据并没有刷新。

在执行fork时,创建子进程,紧接着就是进程退出,进程退出默认刷新缓冲区。此时发生写时拷贝后面退出的进程会再刷新一份,所以最终数据显示了两份

2.3.write调用没有显示两份的原因

write是系统调用接口,上面的过程都是采用的用户级语言层面给我们提供的缓冲区,write使用的不是FILE而是fd,更加底层。


3.模拟实现文件缓冲区

通过myFileBuffer.h和myFileBuffer.c两个文件,模拟实现语言级文件缓冲区FILE

3.1 myFileBuffer.h

  1 #pragma once2 #include<string.h>3 #include<sys/types.h>4 #include<sys/stat.h>5 #include<fcntl.h>6 #include<unistd.h>7 #include<assert.h>8 #include<errno.h>9 #include<stdlib.h>10 11 #define SIZE 1024                                                                                                                                            12           13 //刷新方式        14 #define SYNC_NOW 1 15 #define SYNC_LINE 216 #define SYNC_FULL 417                      18 typedef struct FILE_{ 19   int flags;//刷新方式   20   int fileno;//文件描述符21   int cap;//buffer总容量       22   int size;//buffer当前的使用量23   char buffer[SIZE];24 }_FILE;25                                                     26 _FILE* fopen_(const char*path_name,const char*mode);27 void fwrite_(const void *ptr,int num,_FILE *fp);28 void fclose_(_FILE* fp);29 void fflush_(_FILE *fp);

3.2 myFileBuffer.c

  1 #include"myFileBuffer.h"                                                                     2                                                                                                    3 _FILE* fopen_(const char*path_name,const char*mode){                                                  4                                                                                                      5   int flags=0;                                                                                    6   int defaultMode=0666;                                                                            7                                                                                                    8   //判断不同的打开方式设置flags 这里举例w a r                                                     9   if(strcmp(mode,"r")==0)                                                                          10   {                                                                              11     flags=O_RDONLY;                                                         12                                                                                  13   }                                                                                        14   else if(strcmp(mode,"w")==0)                                                                     15   {                                                                                                 16     flags=O_WRONLY|O_CREAT|O_TRUNC;                                                                 17   }                                                                              18   else if(strcmp(mode,"a")==0)                                                                        19   {                                                                                                    20     flags=O_WRONLY|O_CREAT|O_APPEND;                                                                      21   }                                                                                                      22   else{                                                                                                         23                                                                                                      24   }   26   //根据不同的打开方式,打开文件                                                                                                     27   int fd=0;                                                                                                                      28   if(flags&O_RDONLY)29   {                                                                                                      30     fd=open(path_name,flags);                                                                                                                                31   }                                                                              32   else{                                                                     33     fd=open(path_name,flags,defaultMode);                                   34   }35 36   //printf("我的fd是 %d\n",fd);37   //如果打开失败38   if(fd<0)39   {40     const char* err=strerror(errno);41     write(2,err,strlen(err));42     return NULL;43   }44 45   //创建文件缓冲区并对其初始化46   _FILE*fp=(_FILE*)malloc(sizeof (_FILE));47   assert(fp);48   fp->flags=SYNC_LINE;//默认设置成行刷新49   fp->fileno=fd;50   fp->cap=SIZE;51   fp->size=0;52   memset(fp->buffer,0,SIZE);//初始化文件缓冲区53 54   return fp;55 }56 57 void fwrite_(const void *ptr,int num,_FILE *fp)                                                                                                              58 {59   //写到文件缓冲区中60   memcpy(fp->buffer+fp->size,ptr,num);//注意这里的起始地址61   fp->size+=num;62 63 //  printf("fd->fileno是 %d\n",fp->fileno);64 65   //判断是否刷新66   if(fp->flags&SYNC_NOW)67   {68     //立即刷新69     write(fp->fileno,fp->buffer,fp->size);70     fp->size=0;71   }72   else if(fp->flags&SYNC_FULL)73   {74     //等到缓冲区写满再刷新75     if(fp->size==fp->cap)76     {77       write(fp->fileno,fp->buffer,fp->size);78       fp->size=0;79     }80   }81   else if(fp->flags&SYNC_LINE)82   {83     if(fp->buffer[fp->size-1]=='\n')84     {                                                                                                                                                        85    //   printf("这里是行缓冲\n");86 87       write(fp->fileno,fp->buffer,fp->size);88       fp->size=0;89       //把_FILE缓冲区的内容拷贝到内核缓冲区中90     } 91   }92   else{93 94   }95 96 }97 void fclose_(_FILE* fp)98 {99   //文件退出前会强制刷新
100   fflush_(fp);
101   close(fp->fileno);
102 }
103 void fflush_(_FILE *fp)
104 {
105   //强制刷新
106   if(fp->size>0)
107   {
108     write(fp->fileno,fp->buffer,fp->size);
109     fp->size=0;
110   }
111 }

4.系统内核缓冲区

os的刷新策略很复杂,是权衡自己整体的内存使用情况来进行相应的刷新,并不是上文所讲述的简单的刷新方法。这与用户无关。

整体过程就是:

把内容由用户代码拷贝到 C语言的缓冲区中,再由C语言缓冲区拷贝到内核缓冲区,再有内核缓冲区刷新到外设。


最后

加油

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/458350.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

PIL Image 使用详解

文章目录 1. 各种图像处理库介绍1.1 读取数据的通道顺序1.2 Python图像处理库&#xff08;PIL、Pillow、Scikit-image、Opencv&#xff09; 2、PIL库与Pillow库的区别3 Pillow库3.1 Pillow库特点3.2 Pillow库安装 4、Pillow的Image对象&#xff08;PIL.Image&#xff09;4.1 Im…

bpmn.js一个基于Bpmn 2.0的前端工作流展示和绘制工具

bpmn.js是由开源工作流引擎camunda内部组织BPMN.IO组织开发的一款基于BPMN 2.0的工作流展示、编辑的web端工具库。由于工作流引擎activiti、flowable、camunda属于同宗分流&#xff0c;其工作流定义格式大致相同&#xff0c;所以我们可以使用bpmn.js完美融合其中任一工作流引擎…

java内部类概述及使用方法

前言&#xff1a; 打好基础&#xff0c;daydayup! 内部类 内部类概述&#xff1a; 内部类是类的五大成分之一&#xff08;成员变量&#xff0c;方法&#xff0c;构造器&#xff0c;内部类&#xff0c;代码块&#xff09;&#xff0c;如果一个类定义在另一个类的内部&#xff…

AWS创建快照定期备份

备注&#xff1a;aws有快照定期备份工具&#xff0c;名字叫【生命周期管理器】 选择实例点击创建 点击下一步后设置备份频率等 然后点击创建即可

PCIe学习笔记(1)Hot-Plug机制

文章目录 Hot-Plug InitHot Add FlowSurprise Remove FlowNPEM Flow Hot-Plug Init PCIe hot-plug是一种支持在不关机情况下从支持的插槽添加或删除设备的功能&#xff0c;PCIe架构定义了一些寄存器以支持原生热插拔。相关寄存器主要分布在Device Capabilities, Slot Capabili…

Swift Combine 发布者publisher的生命周期 从入门到精通四

Combine 系列 Swift Combine 从入门到精通一Swift Combine 发布者订阅者操作者 从入门到精通二Swift Combine 管道 从入门到精通三 1. 发布者和订阅者的生命周期 订阅者和发布者以明确定义的顺序进行通信&#xff0c;因此使得它们具有从开始到结束的生命周期&#xff1a; …

vue 实现一个持续时间定时器组件

vue 实现一个定时器组件 效果图子组件父组件 效果图 子组件 新建一个timer.vue文件 <template><span :class"{red: string > 600}">{{ string | formatDurationS }}</span> </template> <script>export default {name: timer,pro…

AD域国产替代方案,助力某金融企业麒麟信创电脑实现“真替真用”

近期收到不少企业客户反馈采购的信创PC电脑用不起来&#xff0c;影响信创改造的进度。例如&#xff0c;某金融企业积极响应国产化信创替代战略&#xff0c;购置了一批麒麟操作系统电脑。分发使用中发现了如下问题&#xff1a; • 当前麒麟操作系统电脑无法做到统一身份认证&…

推荐一款开源的跨平台划词翻译和OCR翻译软件:Pot

Pot简介 一款开源的跨平台划词翻译和OCR翻译软件 下载安装指南 根据你的机器型号下载对应版本&#xff0c;下载完成后双击安装即可。 使用教程 Pot具体功能如下&#xff1a; 划词翻译输入翻译外部调用鼠标选中需要翻译的文本&#xff0c;按下设置的划词翻译快捷键即可按下输…

格式工厂怎么转换视频格式?轻松转换!只需几个步骤

在当今数字娱乐时代&#xff0c;视频格式的广泛多样性意味着我们可能需要在不同设备和平台之间进行频繁的转换。而在众多视频转换工具中&#xff0c;格 式工厂凭借其强大的功能和简便的操作&#xff0c;成为了许多用户首选的选择之一。如果您正在寻找一种轻松而高效的方法来转换…

力扣精选算法100道——和为 K 的子数组[前缀和专题]

和为K的子数组链接 目录 第一步&#xff1a;了解题意​编辑 第二步&#xff1a;算法原理 第三步&#xff1a;代码 第一步&#xff1a;了解题意 数组中和为k的连续子数组&#xff0c;我们主要关注的是连续的&#xff0c; 比如[1,1,1],和为2的子数组有俩个&#xff0c;比如第…

闲聊电脑(6)装个 Windows(二)

闲聊电脑&#xff08;6&#xff09;装个 Windows&#xff08;二&#xff09; 夜深人静&#xff0c;万籁俱寂&#xff0c;老郭趴在电脑桌上打盹&#xff0c;桌子上的小黄鸭和桌子旁的冰箱又开始窃窃私语…… 小黄鸭&#xff1a;冰箱大哥&#xff0c;上次说的镜像文件到底长啥样…