【Linux】用户级缓冲区

news2024/12/25 9:16:51

在这里插入图片描述

👦个人主页:Weraphael
✍🏻作者简介:目前正在学习c++和算法
✈️专栏:Linux
🐋 希望大家多多支持,咱一起进步!😁
如果文章有啥瑕疵,希望大佬指点一二
如果文章对你有帮助的话
欢迎 评论💬 点赞👍🏻 收藏 📂 加关注😍


目录

  • 一、缓冲区现象
  • 二、缓冲区的刷新策略
  • 三、为什么要有缓冲区
  • 四、缓冲区在哪
  • 五、缓冲区 + fork

一、缓冲区现象

以下代码使用了C语言库函数如printffprintffwrite以及系统调用接口write,它们都是向显示器文件打印相应的语句,最后在程序结束之前将显示器文件关闭。

请添加图片描述

请添加图片描述

由上图我们发现:而我们非常好奇的是,首先能保证先是调用打印语句,最后再关闭显示器文件,那么为什么调用C语言的函数没有在显示器上显示结果(重定向也一样)?而程序却打印出系统调用接口write对应的语句!

而且非常奇怪的是:以上printf等C语言库函数不是封装了系统调用write吗?按道理write打印出结果,那么C语言函数也会打印出结果呀?

因此,我们能肯定的是:数据存储在缓冲区中,只是没有被刷新出来!并且这个缓冲区一定不在操作系统内部(不是系统级缓冲区),如果在的话,printf底层调用write就把结果显示出来了。因此,这个缓冲区是用户级缓冲区

请添加图片描述

  • 当调用系统调用接口 write 时,实际上是向操作系统发出了一个写入文件的请求,而操作系统会负责将数据直接写入到文件中。此过程仍然会经过操作系统内核的缓冲区,这部分由操作系统帮我们做的。

  • printf 等接口不会直接将内容直接写入文件中,而是将数据写入到用户空间的缓冲区,然后通过一定条件,再将缓冲区的内容写入到文件中。主要是提高IO效率。

因此我们就可以解释为什么C语言接口打印不出结果的原因了:首先调用printf等接口是将数据写到用户级缓冲区了,而缓冲区正在等待条件将内容通过write写入到文件中,可是半路上遇到了close(1),即显示器文件关闭,而数据还在缓冲区没有被刷新出来,自然而然就无法在显示器上显示。

二、缓冲区的刷新策略

  • 无缓冲:直接刷新。即直接调用write接口将缓冲区的内容写在文件缓冲区(操作系统)中,如直接调用fflush函数刷新缓冲区。
  • 行缓冲:缓冲区不刷新,直到遇到'\n'才刷新缓冲区。默认向显示器文件打印的刷新策略就是行刷新。
  • 全缓冲:缓冲区不刷新,直到缓冲区满了才刷新缓冲区。向文件写入的刷新策略就是全缓冲。
  • 进程退出会强制刷新缓冲区。(特殊情况)

因此,刷新本质就是缓冲区满足某个条件后,可以通过调用write函数写入到文件中

三、为什么要有缓冲区

如果用户想要向一个文件读写数据,由于文件存储在磁盘中,那么要访问文件必定要访问磁盘。然而根据存储金字塔原理,磁盘访问的速度非常慢!若每次向文件读写一次内容,就要和磁盘进行一次IO,效率就十分低下。

因此就有了缓冲区的概念:缓冲区其实就是一段内存空间,用于存储临时数据。需要注意的是,用户级缓冲区通常是通过动态内存分配函数(如 mallocnew)在堆区分配的,大小是不固定的。

当向文件写入时,会将数组先存储到缓冲区中,当达到一定条件,才会写入到文件中。这样就可以减少对磁盘的访问,大大提高了读写效率。

感性理解:如果这个世界上没有快递公司,那么你寄东西就要亲自寄,浪费的是你的时间;而如果有快递公司,你只需要把快递交给快递公司即可,让快递公司帮你寄,转而你可以做你自己的事情。因此,你就相当于进程,而快递就相当于缓冲区。因此,缓冲区的出现大大提高了用户效率。而快递公司并不是拿到你的快递就马上派送,而是等待一定的条件(如用户加急、仓库满了等情况)才寄出。因此,缓冲区的出现可以集中处理数据,减少IO的次数

四、缓冲区在哪

以C语言为例(每个编程语言都一样),我们知道C语言中文件操作通常都是通过 FILE 结构体来进行的,因此,FILE 结构体一定包含了有关文件的信息,包括文件描述符、缓冲区等。

我们可以打开/usr/include/libio.h来看看源码

请添加图片描述

五、缓冲区 + fork

以下有一个非常有趣的代码

请添加图片描述

程序直接运行的话是这样的

请添加图片描述

但如果对进程实现输出重定向呢? 我们发现结果变成了:

请添加图片描述

我们发现:C语言调用的函数均输出了2次,而系统调用write只输出了一次。为什么呢?这肯定和fork有关!

  • 当程序运行时,是直接向显示器文件写入,而写入显示器文件的刷新策略是行缓冲,即遇到\n就会刷新。

  • 当重定向到普通文件时,C库函数写入文件由行缓冲变为全缓冲,因此虽然有\n,但全缓冲的特点是缓冲区满了才会刷新(无视\n)。

  • fork()系统调用会创建一个子进程,该子进程是父进程的副本,所以在fork()之后,子进程会与父进程共享相同的内存空间。这意味着fork()调用后,子进程会继承父进程的用户级缓冲区。当子进程退出时,强制刷新用户层缓冲区[子进程],此时会触发写时拷贝机制;当父进程结束后,强制刷新用户层缓冲区[父进程],因此,C语言调用的函数均输出了2次。而write只打印了一份,也证明了它不经过用户级缓冲区。

请添加图片描述

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

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

相关文章

【linux】详解linux权限

目录 用户 文件属性 更改文件权限 更改文件拥有者 更改文件所属组 用户的权限 文件掩码 粘滞位 总结 基本指令可参考: 【linux】详解linux基本指令-CSDN博客 【linux】详解linux基本指令-CSDN博客 用户 超级用户(root)&#xff…

【C++算法】BFS解决多源最短路问题相关经典算法题

1.01矩阵 既然本章是BFS解决多源最短路问题,也就是说有若干个起点,那我们就可以暴力一点,直接把多源最短路径问题转化成若干个单源最短路径问题,然后将每次的步数比较一下,取到最短的就是最短路径的结果,这…

安卓部署ffmpeg全平台so并实现命令行调用

安卓 FFmpeg系列 第一章 Ubuntu生成ffmpeg安卓全平台so 第二章 Windows生成ffmpeg安卓全平台so 第三章 生成支持x264的ffmpeg安卓全平台so 第四章 部署ffmpeg安卓全平台so并使用(本章) 文章目录 安卓 FFmpeg系列前言一、添加so1、拷贝ffmpeg到项目2、bu…

华为CE6851-48S6Q-HI升级设备版本及补丁

文章目录 升级前准备工作笔记本和交换机设备配置互联地址启用FTP设备访问FTP设备升级系统版本及补丁 升级前准备工作 使用MobaXterm远程工具连接设备,并作为FTP服务器准备升级所需的版本文件及补丁文件 笔记本和交换机设备配置互联地址 在交换机接口配置IP&#…

文件传输服务应用1——java集成smb2/3实现文件共享方案详细教程和windows共享服务使用配置

在实际项目开发过程中,读取网络资源或者局域网内主机的文件是必要的操作和需求。而FTP(文件传输协议)和SMB(服务器消息块)是两种最为常见的文件传输协议。它们各自在文件传输领域拥有独特的优势和特点,但同…

3DMax

先转换为可编辑多边形 按“1”选择为点,点击目标焊接(CtrlShiftw),然后点击一个顶点拉到另一个定点上; 选择一个面,点击塌陷(CtrlAltC),四点合并为一个点; …

Ai指令-公众号内训课:学会ai指令+公众号的底层逻辑(7节课)

课程目录 第一课:详解公众号的流量机制.mp4 第二课:快速搞定公众号号设化装修.mp4 第三课:一期学员直呼牛X的课程,正确的爆文利用姿势.mp4 第五课:颗粒度级别拆解AI公众号爆文.mp4 第六课:AI提示词进阶技巧课。提示词自动化.mp4 第七课.实操演示提示词撰写工作…

element-ui输入框和多行文字输入框字体不一样解决

element-ui的type"textarea"的字体样式与其他样式不同 <el-input type"textarea"></el-input> <el-input ></el-input>设置&#xff1a; .el-textarea__inner::placeholder {font-family: "Helvetica Neue", Helvetic…

GPIO模拟spi时序点亮数码管

目录 spi.h spi.c main.c 实验效果 spi.h #ifndef __SPI_H__ #define __SPI_H__#include "stm32mp1xx_gpio.h" #include "stm32mp1xx_rcc.h"//spi初始化 void spi_init(); //spi写入数据 void spi_write(unsigned char data);#endif spi.c #include…

C#编程-.NET Framework使用工具类简化对象之间的属性复制和操作

在C#编程中&#xff0c;对象之间的属性复制和操作是一个常见的需求。为此&#xff0c;.NET Framework提供了多种实用工具库&#xff0c;如AutoMapper、ValueInjecter和ExpressMapper。这些库通过简化代码&#xff0c;提高了开发效率。本文将介绍这些工具库&#xff0c;比较它们…

Html基础笔记

Html超文本标记语言 (HyperText Markup Language) 超文本 指的是网页中可以显示的内容(图片,超链接,视频,) 标记语言 标记–>标签(标注) 例如:买东西的时候—>商品具有标签,看到标签就知道商品的属性(价格,材质,型号等,) 标记语言就是提供了很多的标签,不同的标签…

Android 几个简单的自定义对话框介绍

Android 几个简单的自定义对话框介绍 文章目录 一、前言二、对话框相关内容1、效果2、对话框显示的调用代码&#xff08;1&#xff09;原生对话框代码&#xff1a;&#xff08;2&#xff09;自定义对话框代码&#xff1a; 3、对话框SweetAlertDialog 主要实现代码&#xff1a;4…

在DAYU200上实现OpenHarmony跳转拨号界面

一、简介 日常生活中&#xff0c;打电话是最常见的交流方式之一&#xff0c;那么如何在OpenAtom OpenHarmony&#xff08;简称“OpenHarmony”&#xff09;中进行电话服务相关的开发呢&#xff1f;今天我们可以一起来了解一下如何通过电话服务系统支持的API实现拨打电话的功能…

噱头还是风口?剖析AI短剧出海的未来

导语 |去年以来&#xff0c;低成本、高回报的土味短剧在国内爆火&#xff0c;而这股风也成功地刮到海外。2024 年&#xff0c;越来越多的人把目光投向了拥有庞大市场的国外“蓝海”&#xff0c;当人们还在高谈阔论 Sora 是否颠覆影视行业的时候&#xff0c;AI 已经在出海短剧中…

Linux系统搭建Tale个人博客网站并实现无公网IP访问本地博客

文章目录 前言1. Tale网站搭建1.1 检查本地环境1.2 部署Tale个人博客系统1.3 启动Tale服务1.4 访问博客地址 2. Linux安装Cpolar内网穿透3. 创建Tale博客公网地址4. 使用公网地址访问Tale 前言 今天给大家带来一款基于 Java 语言的轻量级博客开源项目——Tale&#xff0c;Tale…

【嵌入式芯片开发】不使用MicroLib的串口重定向万能预编译配置(适用于ARMCC、AC6等不同的编译器及版本)

【嵌入式芯片开发】不使用MicroLib的串口重定向万能预编译配置&#xff08;适用于ARMCC、AC6等不同的编译器及版本&#xff09; 文章目录 基本的串口重定向接收中断与scanf不能同时工作重定向卡死、低功耗一直唤醒 串口重定向万能预编译配置附录&#xff1a;Cortex-M架构的Sys…

【设计模式深度剖析】【5】【创建型】【原型模式】| 类比群发邮件,加深理解

&#x1f448;️上一篇:建造者模式 | 下一篇:创建型设计模式对比&#x1f449;️ 目录 原型模式(Prototype Pattern)概览定义英文原话直译 3个角色类图1. 抽象原型&#xff08;Prototype&#xff09;角色2. 具体原型&#xff08;Concrete Prototype&#xff09;角色3. 客户…

【cocos creator 】生成六边形地图

想要生成一个六边形组成的地图 完整代码示例 以下是完整的代码示例&#xff0c;包含了注释来解释每一步&#xff1a; cc.Class({extends: cc.Component,properties: {hexPrefab: {default: null,type: cc.Prefab},mapWidth: 10, // 网格的宽度&#xff08;六边形的数量&am…

基于Pytorch框架全连接神经网络对手势图片识别

欢迎大家点赞、收藏、关注、评论啦 &#xff0c;由于篇幅有限&#xff0c;只展示了部分核心代码。 文章目录 一项目简介 二、功能三、系统四. 总结 一项目简介 一、项目背景与意义 手势识别是计算机视觉领域的一个重要研究方向&#xff0c;具有广泛的应用前景&#xff0c;如人…

react中怎么为props设置默认值

在React中&#xff0c;你可以使用ES6的类属性&#xff08;class properties&#xff09;或者函数组件中的默认参数&#xff08;default parameters&#xff09;来定义props的默认值。 1.类组件中定义默认props 对于类组件&#xff0c;你可以在组件内部使用defaultProps属性来…