【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.mzph.cn/news/671940.shtml

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

相关文章

Linux操作系统运维-Docker的基础知识梳理总结

Linux操作系统运维-Docker的基础知识梳理总结 docker用来解决不同开发人员软件调试时环境不统一的问题&#xff0c;保证了程序调试时运行环境的一致性。docker的设计理念便是一处镜像&#xff0c;处处运行&#xff0c;即通过产生用户软件&#xff0c;运行环境及其运行配置的统一…

回归预测 | Matlab实现ABC-BP人工蜂群算法优化BP神经网络多变量回归预测

回归预测 | Matlab实现ABC-BP人工蜂群算法优化BP神经网络多变量回归预测 目录 回归预测 | Matlab实现ABC-BP人工蜂群算法优化BP神经网络多变量回归预测预测效果基本描述程序设计参考资料 预测效果 基本描述 1.Matlab实现ABC-BP人工蜂群算法优化BP神经网络多变量回归预测&#x…

Linux下centos操作系统安装Mysql8.0过程及踩坑填补

我自己有一台服务器&#xff0c;之前安装的是MySQL5.5&#xff0c;现在我想升级为MySQL8.0&#xff0c;于是我干了以下操作,既有踩坑又有干货&#xff1a; 1.先卸载MySQL&#xff1b; 2.删除跟MySQL相关文件&#xff1b; 3.安装新的MySQL8.0版本&#xff08;这里踩了一个坑&…

Spring- FactoryBean接口中的getObject()方法

目录 一、Spring框架介绍 二、FactoryBean接口是什么 三、getObject()方法如何使用 一、Spring框架介绍 Spring框架是一个轻量级的、非侵入式的Java企业级应用开发框架&#xff0c;以IoC&#xff08;控制反转&#xff09;和AOP&#xff08;面向切面编程&#xff09;为核心思…

springboot集成easypoi导出多sheet页

pom文件 <dependency><groupId>cn.afterturn</groupId><artifactId>easypoi-base</artifactId><version>4.1.0</version> </dependency> 导出模板&#xff1a; 后端代码示例&#xff1a; /*** 导出加油卡进便利店大额审批列…

云计算 - 弹性计算技术全解与实践

一、引言 在过去的十年里&#xff0c;云计算从一个前沿概念发展为企业和开发者的必备工具。传统的计算模型通常局限于单一的、物理的位置和有限的资源&#xff0c;而云计算则通过分布式的资源和服务&#xff0c;为计算能力带来了前所未有的"弹性"。 弹性&#xff1a;…

axios get 请求 url 转码 空格转成+,导致请求失败(前端解决)

问题 GET 请求参数&#xff1a; URL-encoded 后&#xff1a; 浏览器将空格转成了&#xff0c;导致服务报错&#xff0c;返回 400。 解决 在请求拦截器中&#xff0c;对 params 进行处理。 axios.interceptors.request.use((config) > {let url config.url;if (config…

ES监控方法以及核心指标

文章目录 1. 监控指标采集1.1 部署elasticsearch_exporter1.2 prometheus采集elasticsearch_exporter的暴露指标1.3 promethues配置告警规则或者配置grafana大盘 2. 核心告警指标2.1 es核心指标2.2 es容量模型建议 3. 参考文章 探讨es的监控数据采集方式以及需要关注的核心指标…

python-自动化篇-办公-一键将word中的表格提取到excel文件中

文章目录 代码 工作中&#xff0c;经常需要将Word文档中的表格粘贴到Excel文件中&#xff0c;以便汇总及分析。一个一个复制粘贴&#xff0c;非常不方便&#xff0c;还是Python自动化操作&#xff0c;省心省力。要求如下图所示&#xff0c;即将word中的所有表格&#xff0c;转存…

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

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

VMware虚拟机安装openEuler系统(一)(2024)

目录 一、下载ISO镜像 二、开始创建虚拟机 通过实践是学习openEuler开源Linux系统的最佳方式。因此我们首先得搭建一个openEuler实战环境&#xff0c;文章是在Windows系统上使用VMware Workstation虚拟化软件&#xff0c;安装和学习openEuler开源Linux操作系统。 使用虚拟机…

【wu-lazy-cloud-network】Java自动化内网穿透

项目介绍 wu-lazy-cloud-network 是一款基于&#xff08;wu-framework-parent&#xff09;孵化出的项目&#xff0c;内部使用Lazy ORM操作数据库&#xff0c;主要功能是网络穿透&#xff0c;对于没有公网IP的服务进行公网IP映射 使用环境JDK17 Spring Boot 3.0.2 功能 1.内网…

算法day12

算法day12 二叉树理论基础114 二叉树的前序遍历145 二叉树的后序遍历94 二叉树的中序遍历迭代法 二叉树理论基础 直接看代码随想录就完事了&#xff0c;之前考研也学过&#xff0c;大概都能理解 我这里就说说代码层面的。 二叉树的存储&#xff1a; 1、链式存储&#xff1a;这…

基础面试题整理6之Redis

1.Redis的应用场景 Redis支持类型&#xff1a;String、hash、set、zset、list String类型 hash类型 set类型 zset类型 list类型 一般用作缓存&#xff0c;例如 如何同时操作同一功能 2.redis是单线程 Redis服务端(数据操作)是单线程&#xff0c;所以Redis是并发安全的,因…

Mysql MGR搭建

一、架构说明 1.1 架构概述 MGR(单主)VIP架构是一种分布式数据库架构&#xff0c;其中数据库系统采用单主复制模式&#xff0c; 同时引入虚拟IP(VIP)来提高可用性和可扩展性。 这种架构结合了传统主从复制和虚拟IP技术的优势&#xff0c;为数据库系统提供了高可用、 高性能和…

十分钟GIS——geoserver+postgis+udig从零开始发布地图服务

1数据库部署 1.1PostgreSql安装 下载到安装文件后&#xff08;postgresql-9.2.19-1-windows-x64.exe&#xff09;&#xff0c;双击安装。 指定安装目录&#xff0c;如下图所示 指定数据库文件存放目录位置&#xff0c;如下图所示 指定数据库访问管理员密码&#xff0c;如下图所…

uniapp canvas游标卡尺效果

效果 根据公司业务仿照写的效果。原项目从微信小程序转uniapp,未测试该效果在android端效果。 uniapp直接使用canvas不可做子组件,否则无效果显示,其次显示时要考虑页面渲染超时的问题。 如效果所见,可以设置取值精度。 gitee地址:project_practice: 项目练习 - Gitee.…

用python编写爬虫,爬取房产信息

题目 报告要求 工程报告链接放在这里 https://download.csdn.net/download/Samature/88816284使用 1.安装jupyter notebook 2.用jupyter notebook打开工程里的ipynb文件&#xff0c;再run all就行 注意事项 可能遇到的bug 暂无&#xff0c;有的话私信我

Java 中使用多线程的方式有哪些

在 Java 中&#xff0c;使用多线程主要有以下几种方式&#xff1a; 实现 Runnable 接口&#xff1a;这是实现多线程的一种方式。一个类实现 Runnable 接口后&#xff0c;就意味着它是一个线程的执行对象。当一个线程启动时&#xff0c;需要一个与之关联的 Runnable 对象。 publ…

Netflix Mac(奈飞mac客户端) v2.13.0激活版

Clicker for Netflix Mac版是一款适用于Mac的最佳独立Netflix播放器&#xff0c;具有直接从从Dock启动Netflix&#xff0c;从触摸栏控制Netflix&#xff0c;支持画中画等多种功能&#xff0c;让你拥有更好的观看体验。 软件特色 •直接从Dock启动Netflix •从触摸栏控制Netflix…