Linux:缓冲区的概念理解

文章目录

  • 缓冲区
    • 什么是缓冲区?
    • 缓冲区的意义是什么?
    • 缓冲区的刷新方式
  • 理解缓冲区
  • 用户缓冲区和内核缓冲区
  • 缓冲区在哪里?

本篇主要总结的是关于缓冲区的概念理解,以及再次基础上对文件的常用接口进行一定程度的封装

缓冲区

什么是缓冲区?

如何理解缓冲区?简单来说,缓冲区就是一段内存,用来存放一些信息,这就是对于缓冲区最初步的理解。那如何证明缓冲区的存在?用下面的代码来验证缓冲区

#include <stdio.h>
#include <unistd.h>void buffertest()
{printf("hello linux");sleep(3);
}int main()
{buffertest();return 0;
}

在这里插入图片描述
现象

运行结果如上所示,会先休眠三秒再输出结果,按程序的顺序结构来说,sleep一定是在printf之后执行的,也就意味着当执行到sleep的时候运行结果已经被写到了某个地方,只是还没有刷新到显示器上,因此用户看不见显示的内容,而当sleep执行完毕后,此时会把内容刷新到显示器上,这样就能看到运行的结果了

解释

而在执行了printf函数后其实就已经把内容输出了,输出的地方其实就是缓冲区中,只是还没有将信息存储到显示器这个文件内,因此没有输出结果,而当进程结束后,就会把缓冲区中的信息都刷新到显示器中,此时就实现了把信息打印到显示器上,所以才会看到,程序运行后没有输出结果,而是在执行完sleep后才会输出到显示器上

缓冲区的意义是什么?

如何理解缓冲区?有了这个缓冲区能干什么呢?答案是提高效率,对于这个答案其实并不陌生,在前面的学习中也存在有关于缓冲区的概念,只是对于缓冲区的认知程度比较低

举个例子来说,现在用户在上层使用C语言打印了很多信息,但是没有发出要刷新的需求,那么此时这些信息就都会存储在缓冲区中,而当缓冲区满了或者触发其他的刷新策略的时候,就会统一把缓冲区中的信息转移到内存中,再由内存进行其他后续的操作,在本文的后面会对这一整体的操作进行分析,此处只进行初步的描述

从外部把信息存储到内存中是需要成本的,而缓冲区的存在就是把这些信息积攒到一定程度再进行发送,既然设计出缓冲区的存在,那么就意味着把信息从缓冲区发送到内存中比直接把信息发送到内存中需要付出的成本低,这样可以提高运输的效率

缓冲区的刷新方式

缓冲区可以暂存数据,就意味着一定会有对应的刷新方式

  1. 无缓冲(立即刷新)
  2. 行缓冲(行刷新)
  3. 全缓冲(缓冲区满了才刷新)

一般而言是可以使用上面的刷新策略的,但是在实际的进程运行过程中可能会出现其他的意外情况,例如:

  1. 强制刷新
  2. 进程退出了,一般会刷新缓冲区

一般而言,对于显示器文件会采用的是行刷新策略,而对于磁盘上的文件会采用全缓冲的策略,对于这两种不同的刷新策略下一个模块就进行分析

理解缓冲区

下面来看这样的测试代码样例

void buffertest2()
{fprintf(stdout, "C:hello fprintf\n");printf("C:hello printf\n");fputs("C:hello fputs\n", stdout);const char* str = "system call: hello write\n";write(1, str, strlen(str));fork();
}

运行结果:

在这里插入图片描述
将运行结果输出到另外一个文件中

在这里插入图片描述
此时会发现有异常现象出现了,对于C语言的接口会打印输出两套,而对于系统调用的接口只会输出一套,那么这是为什么呢?为什么要在代码中进行fork的操作呢?fork的操作会带来怎样的影响?这两种现象出现的原因是什么呢?

对于上述现象的理解和解释

  1. 首先,对于上面的异常现象,要从出现异常的操作出发,为什么会出现异常?原因是一个是将内容直接执行,运行到显示器上,一个是把执行的结果输出到一个文件中,那么这两个操作会带来区别吗?答案是一定会的,原因就是前面提到的刷新方式的变换,对于显示器来说是行刷新策略,对于磁盘来说是全刷新策略,那么这就会带来不一样的结果,具体的原因后续分析
  2. 全缓冲意味着缓冲区会变大,实际写入的简单数据不会把缓冲区写满,因此在执行fork操作的时候,数据依旧在缓冲区中,没有被刷新到文件中
  3. 在上述的代码中所使用到的缓冲区,全部都是C语言的缓冲区,这个缓冲区是C语言本身给我们提供的,因此和操作系统内部提供的缓冲区是两种缓冲区,没有关系
  4. 那么问题来了,这和fork有什么关系呢?fork会带来什么结果呢?
  5. 那么现在就要思考的是,fork会带来什么结果,根据前面的思想不难想到,fork带来的第一个直观的效果就是创建一个子进程,这是不需要质疑的事,而对于这个进程来说,fork结束后带来的另外一个结果就是结束进程,而结束进程带来的结果就是会刷新缓冲区,既然刷新缓冲区了,那么就会把这个进程所对应的缓冲区内容清空,那么下一个问题就是关于写时拷贝的问题,缓冲区清空算不算进程的数据发生改变了呢?如果算发生改变就会发生写时拷贝,如果不算改变就不会,那么下一个问题就是进程的数据在清空缓冲区的时候算不算发生了修改
  6. 要解决上面的这个问题,本质上是思考C语言的缓冲区中的数据算不算进程运行时候的数据,因为写时拷贝的触发原理就是进程运行时候,父进程和子进程中只要有一个进程中的数据被修改,就会给另外一个进程发生写时拷贝,而这里的缓冲区的数据一定是属于进程运行时的数据的,而与此同时需要注意的是,当把数据已经交给操作系统之后,此时数据就是操作系统的,而不是进程本身的数据了,对于这样的数据即使发生修改也并不隶属于写时拷贝的范畴
  7. 那么分析到这里,其实对于上面的这个现象已经理解的很到位了,现在还有最后一个问题,为什么这个进程中对于使用系统调用的数据没有发生写时拷贝,难道这个不算是C语言缓冲区的数据,以至于这个数据不算进程的数据就不会发生写时拷贝吗?答案是肯定的,这是因为缓冲区也有很多类,而除了系统调用外的其他写入的方式都是使用的是C语言自身所提供的一个缓冲区,因此在这样的基础下进行的数据是属于进程的数据的,而使用系统调用的接口使用的数据其实并不属于,它没有使用C语言缓冲区

总结

经过上面的这几条分析,其实已经把缓冲区的概念总结的算是比较到位了,刷新其实就是把C缓冲区的数据写入操作系统

用户缓冲区和内核缓冲区

什么是用户缓冲区,什么是内核缓冲区?

用户缓冲区

用户缓冲区其实就是平时日常的使用中提供的语言级别的缓冲区,在用户层面把信息进行写入,这样的级别就是用户缓冲区所做的事,作为用户上层,进行了一系列的各种写入,这些操作都是在给用户缓冲区中写入信息,而从用户缓冲区再向着操作系统写入信息这个过程,就是刷新,经过刷新就可以把信息写入操作系统,而在操作系统内部,又会有一套完整的文件系统,关于文件系统在上一篇文章中已经完整的描述过内部的过程,这里就不再详细叙述了

内核缓冲区

既然将内容从C语言写到操作系统中需要缓冲区,那么把读取的信息刷新到磁盘中是不是也是需要缓冲区的介入呢?答案是肯定的,这是一定会有的,而这其实也是刷新,把内核缓冲区的数据写到磁盘中,也是一种刷新,只不过刷新策略和前面的C缓冲区不太一样而已,这里就对内核缓冲区不再进行过多的介绍了,它本质和硬件设备相关更多一些

缓冲区在哪里?

那这个缓冲区在哪里呢?其实也是可以找到的,调用指令进行搜索:

whereis stdio.h

打开文件,寻找FILE有关的内容

在这里插入图片描述
那么下一步就是寻找这个结构体究竟在哪里

在这里插入图片描述
在这个libio.h文件中,寻找到了这个内容,而在进行输入和输出的时候,就会有一个FILE,而FILE本质上就是一个结构体,这个结构体叫FILE里面就包含了fd,这个FILE结构体就会提供一段缓冲区

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

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

相关文章

keil添加了头文件仍然报找不到头文件的原因

如图&#xff0c;我在user分组新建Item&#xff0c;可是keil提示头文件不存在&#xff0c;所有的一切设置都是对的&#xff0c;但就是找不到头文件&#xff0c;找了很久&#xff0c;最后才发现是user分组和文件系统中的文件夹不一致的原因。 如图&#xff0c;在分组的文件系统的…

微服务架构之服务发现

在微服务架构中&#xff0c;服务与服务之间需要通过服务发现来找到对方&#xff0c;以便发起请求。 所谓的服务发现就是一种自动监测并发现网络内的的服务的机制。可以调用者动态感知到网络上服务的变化。DNS就是最典型的服务发现系统了。 在微服务架构中的服务发现的工作原理…

【动态规划】03使用最小花费爬楼梯(easy1)

题目链接&#xff1a;leetcode使用最小花费爬楼梯 目录 题目解析&#xff1a; 算法原理 1.状态表示 2.状态转移方程 3.初始化 4.填表顺序 5.返回值 编写代码 题目解析&#xff1a; 题目让我们求达到楼梯顶部的最低花费. 由题可得&#xff1a; cost[i] 是从楼梯第 i 个…

【附源码】完整版,Python+Selenium+Pytest+POM自动化测试框架封装

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 1、测试框架简介 …

【VRTK】【VR开发】【Unity】11-甩臂移动

课程配套学习资源下载 https://download.csdn.net/download/weixin_41697242/88485426?spm=1001.2014.3001.5503 【概述】 除了一般的移动能力,VRTK还提供更为沉浸的甩臂移动。 【设定摇杆输入中间件】 在Hierarchy中展开Button Input Actions,其下生成两个新的空子对象…

看图学源码之 CopyOnWriteArraySet源码分析

基本介绍 使用内部CopyOnWriteArrayList进行所有操作的Set 特点 它最适合以下应用程序&#xff1a;集合大小通常较小、只读操作的数量远远多于可变操作&#xff0c;并且您需要在遍历期间防止线程之间的干扰。它是线程安全的。突变操作&#xff08; add 、 set 、 remove等&…

主动而非被动:确保网络安全运营弹性的途径

金融部门处理威胁的经验对网络安全领域的任何人都有启发——没有什么可以替代提前摆脱潜在的风险和问题。 从狂野西部的银行劫匪到勒索软件即服务 (RaaS)&#xff0c;全球金融生态系统面临的威胁多年来发生了巨大变化。技术进步带动了金融业的快速发展&#xff0c;从现金交易到…

基于轻量级MnasNet模型开发构建40种常见中草药图像识别系统

文本是前文的后续&#xff1a; 《python基于轻量级GhostNet模型开发构建23种常见中草药图像识别系统》 前文主要是在小批量小种类数据集上尝试开发构建基于轻量级CNN模型的中草药图像识别系统&#xff0c;本文的初衷是想要构建一个大类别大数据集的基础&#xff0c;但是无奈发…

附录1、vuepress中的Markdown语法

# 一、标题 # 说明&#xff1a; #后面跟的内容就是标题&#xff0c;一个#就是一级标题&#xff0c;有几个#就是几级标题&#xff0c;例如2级标题就有两个##&#xff0c;markdown的2级和3级标题会默认自动作为子目录&#xff0c; 注意&#xff1a;#后面必须有个空格&#xff0…

【天线了解】2.WTW天线了解与使用

注意网段&#xff1a;&#xff08;计算机与设备同一网段才可以通信&#xff09; 1.LS28接收机使用的网段是192.168.16.X&#xff0c;所以电脑应该同样设置 2.WTW天线使用网段192.168.98.X 0.WTW使用原理 1.计算机控制LS28&#xff08;接收机&#xff09;&#xff0c;WTW天线。 …

全志H6-ARMLinux第1天:全志概述、刷机登陆、官方外设库、蜂鸣器、超声波测距

1. 全志H616课程概述&#xff08;456.01&#xff09; 1.1 为什么学 学习目标依然是Linux系统&#xff0c;平台是ARM架构 蜂巢快递柜&#xff0c;配送机器人&#xff0c;这些应用场景用 C51、STM32 单片机无法实现第三方介入库的局限性&#xff0c;比如刷脸支付和公交车收费设…

《微信小程序开发从入门到实战》学习四十四

4.3 云开发文件存储 4.3.4 删除文件 在小程序端和云函数端&#xff0c;都可以调用API删除云空间中的文件&#xff0c;这两个API的参数和回调函数参数都是一样。每次调用API最多删除50个文件。使用方法如下代码所示&#xff1a; // 回调风格的API wx.cloud.deleteFile({ file…

python的extend函数详解

文章目录 语法功能示例例1&#xff1a;添加列表例2&#xff1a;添加元组例3&#xff1a;添加集合例4&#xff1a;添加字典&#xff08;只添加键&#xff09;例5&#xff1a;添加字符串例6&#xff1a;混合类型扩展例7&#xff1a;扩展空列表或不可迭代对象 注意事项&#xff1a…

PHP使用mkcert本地开发生成HTTPS证书 PhpEnv集成环境

PHP使用mkcert本地开发生成HTTPS证书 PhpEnv集成环境 前言一、介绍 mkcert二、安装/使用 mkcert1. 安装2. 使用 总结 前言 本地开发时有些功能只有在 https 证书的情况下才能使用, 例如一些 Web API 一、介绍 mkcert Github地址 mkcert 是一个制作本地可信开发证书的简单工具。…

SmartChart:一站式数据可视化解决方案

在当今的数据驱动的世界中&#xff0c;数据可视化已经成为了一个重要的工具&#xff0c;它可以帮助我们理解复杂的数据集&#xff0c;并从中提取有价值的信息。SmartChart就是这样一个强大的数据可视化工具&#xff0c;它提供了一站式的数据可视化解决方案&#xff0c;无论你是…

Docker实战笔记 二 Springboot Idea 插件打包

1.上传springboot的jar rootcenots-7.5:/home/code#rz -----app.jar 2.编辑Dockerfile rootcenots-7.5:/home/code#vi Dockerfile内容 FROM openjdk:8 # 作者 MAINTAINER nnd # 声明要使用的端口 EXPOSE 8080 # VOLUME 指定了临时文件目录为/tmp。# 将本地包添加到容器中并…

力扣题:字符的统计-12.7

力扣题-12.7 [力扣刷题攻略] Re&#xff1a;从零开始的力扣刷题生活 力扣题1&#xff1a;467. 环绕字符串中唯一的子字符串 解题思想&#xff1a;记录下以字母s[i]结尾的最大的字串个数&#xff0c;然后统计a-z每个字母结尾的最大字串的个数进行i相加 class Solution(object…

DDD架构思想专栏一《初识领域驱动设计DDD落地》

引言 最近准备给自己之前写的项目做重构&#xff0c;这是一个单体架构的小项目&#xff0c;后端采用的是最常见的三层架构。因为项目比较简单&#xff0c;其实采用三层架构就完全够了。但是呢&#xff0c;小编最近在做DDD架构的项目&#xff0c;于是就先拿之前写的一个老项目试…

1319:【例6.1】排队接水

【题目描述】 有n 个人在一个水龙头前排队接水&#xff0c;假如每个人接水的时间为Ti &#xff0c;请编程找出这n 个人排队的一种顺序&#xff0c;使得n 个人的平均等待时间最小。 【输入】 共两行&#xff0c;第一行为n(1≤n≤1000) &#xff1b;第二行分别表示第1 个人到第n…

从传统到胜利:广汽集团汽车产业创新之旅

置身于汽车行业百年未有之大变局&#xff0c;作为传统车企中的排头兵&#xff0c;广汽创新可圈可点&#xff0c;广汽近年来取得了骄人业绩&#xff0c;不论是整体产销规模&#xff0c;还是新能源汽车产业化、新技术领域开拓等&#xff0c;都呈现节节攀升的局面。本文奖从产业变…