【Linux】缓冲区

目录

一、初识缓冲区

二、用户级缓冲区

三、内核级缓冲区

四、内核级缓冲区 VS 用户级缓冲区

 五、用户级缓冲区在哪里?


一、初识缓冲区

缓冲区是什么?可以简单理解成一部分内存。例如用户缓冲区(char arr[])、C标准库提供的缓冲区、操作系统提供的缓冲区。

为什么要有缓冲区?要通过减少对磁盘的直接访问来提高文件操作的效率。例如给朋友寄快递,不是直接给朋友送过去,而是通过快递站,快递站也不是来一个包裹就送一个包裹,而是积累一部分包裹再统一发送,朋友只用到他对应的快递站取走包裹即可。提高了使用者的效率和发送的效率。

缓冲区能暂存数据,因此也要有一定的刷新方式。(一般策略)

  1. 无缓冲(立即刷新)
  2. 行缓冲(行刷新)
  3. 全缓冲(缓冲区满了,再刷新)
  4. 一般对于显示器文件,行刷新(行缓冲) ;对于磁盘上的文件,全缓冲(缓冲写满,在刷新)

特殊情况:

  1. 强制刷新 
  2. 进程退出的时候,一般要自动刷新缓冲区,即便数据没有满足刷新条件。

强制刷新缓冲区,把当前缓冲区的内容全部刷新。类似于寄快递时对工作人员说:赶快给我发出去,不然就投诉你。这时工作人员就会把驿站当前积累的包裹都发送出去。行刷新,就是把驿站快递柜的一行快递发送。全刷新,就是驿站快递柜满了,把积累的全部包裹发送出去。

看下面一段代码思考结果如何,输出重定向到文件中,结果一样吗?

#include <stdio.h>    
#include <string.h>    
#include <unistd.h>    int main()    
{    printf("C: hello printf\n");    fprintf(stdout, "C: hello fprintf\n");    fputs("C: hello fputs\n",stdout);                                                                            const char* str = "system call: hello write\n";    write(1,str,strlen(str));    fork();    return 0;    
}  

现象:直接执行程序时向显示器打印,C标准库和系统调用的函数都打印一次,但输出重定向到 log.txt 文件时,C标准库提供的函数打印两次,系统调用的函数只打印一次。

原因:

  1. 当我们直接向显示器打印的时候,显示器文件的刷新方式是行刷新!而且代码输出的所有字符串,都有'\n'。fork之前,数据全部已经被刷新,包括systemcall。
  2. 重定向到 log.txt ,本质是向磁盘文件中写入(不是显示器),系统对于数据的刷新方式已经由行缓冲,变成了全缓冲!
  3. 变成全缓冲意味着缓冲区变大,实际写入的简单数据,不足以把缓冲区写满,fork执行的时候数据依旧在缓冲区中!
  4. 我们目前所谈的"缓冲区",和操作系统是没有关系的,只能和C语言有关。(因为系统调用的结果打印正常符合预期,且C 库中的printf、fprintf、fputs实际上还是封装的wirte,如果是因为write引起的,write函数也会打印两次)

二、用户级缓冲区

我们日常用的最多的其实是C/C++标准库提供的语言级别的缓冲区,也叫用户级缓冲区。而操作系统提供的是内核级缓冲区。
在上面的例子中,我们这边的快递站就是C语言提供的用户级缓冲区,朋友就是操作系统,朋友那边的快递站就是内核级缓冲区。

上面代码原理的补充:

  • C/C++标准库提供的缓冲区,里面一定保存的是用户的数据,属于当前进程在运行时的数据。
  • 如果把用户的数据交给操作系统,那么这个数据不属于用户,属于操作系统。
  • 进程退出刷新缓冲区时,要进行刷新缓冲区,这也属于 "清空" 或 "写入" 操作。
  • C/C++缓冲区的数据属于进程的数据、fork后父子进程共享缓冲区数据,当要写入或者任一进程退出时,要刷新缓冲区,此时会发生 "写时拷贝"。
  • 可以证明write系统调用没有使用C的缓冲区,直接写入到操作系统。这个数据不属于进程。

什么叫做刷新?

一个进程有对应的文件描述符表,例如有一个打开的log.txt文件,它加载到内存中,对应一个struct file,文件描述符为3,对应一个文件缓冲区。磁盘上也有一个对应的log.txt。

用户要把"hello"字符串打印到log.txt文件,该字符串是经过fprintf等函数写入到C语言提供的缓冲区(例如名叫buffer),经过fflush或进程退出时,调用write(3,buffer)写入到文件缓冲区中。

把用户的缓冲区(例如字符数组)拷贝到C语言的缓冲区,再把C语言提供的缓冲区的内容拷贝到文件缓冲区,这个过程叫做刷新。

补充:

  • fprintf等函数不仅将打印内容拷贝到缓冲区中,还做了格式化输出操作。这个格式化输出操作是在拷贝时完成的。我们之前用的所有缓冲区都是C语言提供的用户级缓冲区。
  • 直接把数据从用户的缓冲区拷贝到文件缓冲区,成本很高,刷新操作可以提高效率
  • C语言中几乎所有的I/O接口都有缓冲区。
  • 文件缓冲区中的数据需要写入文件系统时,数据再被写入到文件系统的磁盘块中。这也是为了提高效率(减少磁盘访问)。(该操作由OS执行)

经过上面的分析,就可以更好的理解用户级缓冲区的特点:

  • 用户级缓冲区通常位于用户空间,由进程自己管理。
  • 用户级缓冲区的主要目的是提高文件操作的效率,减少系统调用的次数。
    例如,当写入文件时,数据首先被写入用户级缓冲区,然后写入内核级缓冲区,最后写入文件系统。
  • 用户级缓冲区可以被刷新,使用 'fflush' 函数可以手动刷新缓冲区,确保所有数据都被写入文件。
  • C标准库(如stdio.h)提供了文件操作的函数,如 'fopen'、'fread'、'fwrite' 等。这些函数可以在打开文件时指定缓冲区类型,如 '"w+b"'。

以下是C语言提供的几种用户级缓冲区类型:

  • 无缓冲区(无缓冲):使用 '"wb"' 或 '"rb"' 模式打开文件时,文件没有缓冲区。每次调用写入或读取函数时,数据都会立即写入或从文件中读取。
  • 行缓冲区(行缓冲):使用 '"w+b"' 或 '"r+b"' 模式打开文件时,文件有行缓冲区。每写入或读取一行数据时,数据会被缓冲,直到缓冲区满或遇到换行符。
  • 全缓冲区(全缓冲):使用 '"w+"' 或 '"r+"' 模式打开文件时,文件有全缓冲区。写入或读取的数据会被缓冲,直到缓冲区满或调用 'fflush' 函数。 

三、内核级缓冲区

上面讲到的文件缓冲区就是操作系统的内核级缓冲区
内核缓冲区通常位于内核空间,由操作系统直接管理。
标准输出(stdout)和标准错误(stderr)通常使用内核级缓冲区。
内核级缓冲区通常在进程结束时自动刷新,但在某些情况下,可以通过调用 'fflush' 函数来手动刷新这些缓冲区。
内核级缓冲区的主要目的是减少对物理设备的直接访问,提高系统性能。

用户级缓冲区和内核级缓冲区可以同时使用,以提高程序的性能。例如,当读取文件时,数据首先被读取到用户级缓冲区中,然后从用户级缓冲区读取到程序的内存中。当写入文件时,数据首先被写入程序的内存中,然后写入用户级缓冲区,最后写入内核级缓冲区,最终写入文件系统。

四、内核级缓冲区 VS 用户级缓冲区

  • 作用:内核级缓冲区主要用于减少对物理设备的直接访问,提高系统性能;而用户级缓冲区主要用于提高文件操作的效率,减少系统调用的次数。
  • 位置:内核级缓冲区位于内核空间,由操作系统管理;用户级缓冲区位于用户空间,由程序自己管理。
  • 管理:内核级缓冲区由内核直接管理,对用户不可见;用户级缓冲区由程序员控制,可以通过编程方式进行管理。
  • 性能:内核级缓冲区可以显著减少磁盘I/O操作,提高系统性能;用户级缓冲区可以减少系统调用的次数,提高程序的执行效率。

缓冲区在Linux中的主要作用:

  1. 减少磁盘访问:缓冲区允许数据在内存中暂存,而不是每次操作都直接从磁盘读取或写入。这减少了磁盘I/O操作的次数,从而提高了系统的整体性能。
  2. 优化内存使用:缓冲区可以存储大量数据,减少了对物理内存的需求。数据在内存中缓存,可以在需要时快速访问,而不是每次都从磁盘加载。
  3. 减少系统调用次数:缓冲区允许在多个操作之间缓存数据,减少了与文件系统交互的系统调用次数。这减少了内核和用户空间之间的上下文切换,提高了程序的执行效率。
  4. 提高文件操作的效率:缓冲区可以减少对文件的频繁读写,从而提高了文件操作的效率。例如,当编辑一个大型文件时,文本编辑器可以在缓冲区中修改数据,而不是每次修改都写入文件。
  5. 减少延迟:缓冲区可以减少数据传输的延迟,因为数据可以快速地在内存中传递。这使得程序可以更快速地处理数据,尤其是在处理大量数据时。
  6. 支持并行操作:缓冲区可以支持并行操作,例如,多个进程可以同时访问同一个缓冲区。这使得系统可以更有效地利用多核处理器和多进程架构。

 五、用户级缓冲区在哪里?

任何情况下,我们输出输入的时候,都要有一个FILE,FILE是一个结构体,FILE里面包含了fd,也提供了一段缓冲区!因此任何一个文件都要在C标准库里通过FILE创建一个用户级缓冲区。
例如进程打开了5个文件,就有5个FILE对象和struct file,对应5个文件缓冲区,读写时互相不影响。

可以看看C标准库中的FILE结构体:
typedef struct _IO_FILE FILE;  在   /usr/include/stdio.h

在/usr/include/libio.h
struct _IO_FILE {int _flags;     /* High-order word is _IO_MAGIC; rest is flags. */
#define _IO_file_flags _flags//缓冲区相关/* The following pointers correspond to the C++ streambuf protocol. *//* Note: Tk uses the _IO_read_ptr and _IO_read_end fields directly. */char* _IO_read_ptr;     /* Current read pointer */char* _IO_read_end;     /* End of get area. */char* _IO_read_base;     /* Start of putback+get area. */char* _IO_write_base;     /* Start of put area. */
char* _IO_write_ptr;     /* Current put pointer. */char* _IO_write_end;     /* End of put area. */char* _IO_buf_base;     /* Start of reserve area. */char* _IO_buf_end;     /* End of reserve area. *//* The following fields are used to support backing up and undo. */char *_IO_save_base; /* Pointer to start of non-current get area. */char *_IO_backup_base; /* Pointer to first valid character of backup area */char *_IO_save_end; /* Pointer to end of non-current get area. */struct _IO_marker *_markers;struct _IO_FILE *_chain;int _fileno; //封装的文件描述符#if 0int _blksize;
#elseint _flags2;
#endif_IO_off_t _old_offset; /* This used to be _offset but it's too small. */#define __HAVE_COLUMN /* temporary *//* 1+column number of pbase(); 0 is unknown. */unsigned short _cur_column;signed char _vtable_offset;char _shortbuf[1];/* char* _save_gptr; char* _save_egptr; */_IO_lock_t *_lock;
#ifdef _IO_USE_OLD_IO_FILE
};

向显示器打印123的时候,打印的其实是1字符2字符3字符,我们用键盘输入123时,也是输入1字符2字符3字符,这3个字符被放入到stdin对应FILE结构体中的缓冲区。scanf将缓冲区的数据合并,根据用户定义的格式赋给指定的值。键盘显示器也叫字符设备。

C语言把打开的文件叫做流,输入流输出流,流也相当于C语言提供的缓冲区,一方面C语言从缓冲区的头部拿数据,一方面用户在缓冲区尾部追加数据,该操作像流水一样,所以称作‘流’。C++也是同理,也有自己的缓冲区。原理和C相同,但操作上有很大区别。

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

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

相关文章

【算法】网络图中的dfs

快乐的流畅&#xff1a;个人主页 个人专栏&#xff1a;《算法神殿》《数据结构世界》《进击的C》 远方有一堆篝火&#xff0c;在为久候之人燃烧&#xff01; 文章目录 引言一、单词搜索二、黄金矿工三、不同路径 |||四、图像渲染五、岛屿数量六、岛屿的最大面积七、被围绕的区域…

三磷酸腺苷(ATP)制备方法众多 主要应用于生化研究以及医药领域

三磷酸腺苷&#xff08;ATP&#xff09;制备方法众多 主要应用于生化研究以及医药领域 三磷酸腺苷&#xff08;ATP&#xff09;又称腺嘌呤核苷三磷酸、腺苷三磷酸&#xff0c;化学式为C10H16N5O13P3&#xff0c;是一种高能磷酸化合物。腺苷三磷酸外观呈白色粉末&#xff0c;无特…

2025秋招Java还是c++?

一、我的编程经 说说我的编程经历&#xff0c;在C和Java之间我经历了几个阶段&#xff1a; 大学期间&#xff0c;我浅尝辄止地学习了一段时间的Java&#xff0c;但后来放弃了&#xff0c;开始学习C/C。本科毕业后&#xff0c;我选择攻读硕士学位&#xff0c;并一直专注于C的学…

集成了Gemini的Android Studio,如虎添翼

今天将Android Studio升级到最新版&#xff08;Jellyfish&#xff09;。发现在new features中有一条&#xff1a; Code suggestions with Gemini in Android Studio 打开路径为&#xff1a; View > Tool Windows > Gemini 支持多国语言&#xff0c;英文、中文都能正确理解…

PPT为何无法复制粘贴?附解决办法!

PPT文件里的内容无法复制&#xff0c;或者复制后无法粘贴&#xff0c;这是怎么回事呢&#xff1f; 这种情况&#xff0c;一般是因为PPT被设置了保护&#xff0c;设置了以“只读方式”打开&#xff0c;就无法进行复制粘贴了。PPT的“只读方式”不同&#xff0c;解决方法也不同&…

Java入门基础学习笔记25——死循环和循环嵌套

死循环&#xff1a; 可以一直执行下去的一种循环&#xff0c;如果没有干预不会停下来。 死循环的写法&#xff1a; 例&#xff1a; package cn.ensource.loop;public class EndLessLoopDemo5 {public static void main(String[] args) {// 目标&#xff1b;掌握死循环的写法w…

力扣127.单词接龙讲解

距离上一次刷题已经过去了.........嗯............我数一一下............整整十天&#xff0c;今天再来解一道算法题 由于这段时间准备简历&#xff0c;没咋写博客。。今天回来了&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&…

【React】如何让函数式组件也能使用state——useState(Hooks)

React的函数式组件不同于类式组件&#xff0c;函数式组件没有自己的 this&#xff0c;看似没有操作state的能力 但是React官方提供了一个Hooks叫useState&#xff0c;它解决了函数式组件和类式组件的差异&#xff0c;让函数式组件拥有了类式组件所拥有的 state &#xff0c;同时…

在win10折腾Flowise:部署和尝试

Flowise 是一种低代码/无代码拖放工具&#xff0c;旨在让人们轻松可视化和构建 LLM 应用程序。 本地部署 操作系统&#xff1a; win10 由于网络、操作系统等各种未知问题&#xff0c;使用npm install -g flowise的方式&#xff0c;尝试了很多次&#xff0c;都没有部署成功&am…

Visual C++界面开发组件Xtreme Toolkit Pro v24测试版发布——完全支持SVG

Codejock软件公司的Xtreme Toolkit Pro是屡获殊荣的VC界面库&#xff0c;是MFC开发中最全面界面控件套包&#xff0c;它提供了Windows开发所需要的11种主流的Visual C MFC控件&#xff0c;包括Command Bars、Controls、Chart Pro、Calendar、Docking Pane、Property Grid、Repo…

位图和布隆过滤器:位图

在《unordered_map 和 unordered_set》 中提到过&#xff1a; 哈希是一种思想&#xff0c;通过哈希函数将数据转化为一个或多个整型 —— 映射关系&#xff1b;通过这种映射关系&#xff0c;可以做到以 O(1) 的时间复杂度查找数据。 本文即将介绍的 位图 和 布隆过滤器 就是两个…

专“蜀”盛会!CGT Asia 2024 第六届亚洲细胞与基因治疗创新峰会(成都站)7月火热相邀

在细胞与基因治疗领域&#xff0c;我们正站在一个科技革命的风口上。中国的CGT市场预计将持续快速增长。根据相关分析&#xff0c;预计到2025年整体市场规模将达到25.9亿美元&#xff0c;显示出276%的复合年增长率。这一增长趋势预计将持续到2030年&#xff0c;细胞与基因治疗领…

【前端】TypeScript--未整理

概念 安装 npm install -g typescript 检查版本 tsc -v tsc 类型

redis-stack部署概要

第一步&#xff0c;下载redis-stack 下载链接&#xff1a;Downloads - Redis 第二步&#xff0c;redis安装包解压缩 gzip -d redis-stack-server-7.2.0-v10.rhel8.x86_64.tar.gz tar -xvf redis-stack-server-7.2.0-v10.rhel8.x86_64.tar 第三步&#xff0c;编辑etc下的redis…

IC设计企业如何实现安全便捷的芯片云桌面跨网摆渡?

IC设计企业&#xff0c;主要专注于集成电路的设计。这些企业通常包括集成电路、二极管、三极管和特殊电子元件等产品的设计和生产。IC设计企业在其运营和产品设计过程中&#xff0c;会涉及和产生多种文件&#xff0c;如&#xff1a; 项目需求文档&#xff1a;这是项目启动的基础…

停车场车位引导管理系统工作原理是什么,由哪些软硬件设备组成?

在现代城市中&#xff0c;随着汽车保有量的持续增长&#xff0c;停车难成为了许多城市面临的共同问题。有效管理停车场资源&#xff0c;提高车位利用率&#xff0c;减少寻找停车位的时间&#xff0c;对于缓解交通拥堵、提高城市运行效率具有重要意义。车位引导管理系统正是为了…

谷歌举办Gemini API开发者大赛;ChatGPT iOS版更新支持中文

&#x1f989; AI新闻 &#x1f680; 谷歌举办Gemini API开发者大赛&#xff0c;大奖1981款电动DeLorean 摘要&#xff1a;IT之家 5 月 15 日消息&#xff0c;在 2024 年谷歌 I/O 开发者大会上&#xff0c;谷歌宣布举办 Gemini API 开发者大赛&#xff0c;主要面向个人开发者…

24长三角数学建模ABC题已出!!!

需要ABC题资料的宝子们可以进企鹅 赛题如下&#xff1a; 赛道 A&#xff1a;“抢救”落水手机 上有天堂&#xff0c;下在苏杭&#xff1b;五一假期&#xff0c;杭州西湖、西溪湿地、京杭大运河等著名 景点&#xff0c;游人如织&#xff0c;作为享誉国内外的旅游胜地&#xff0…

图形程序复用新纪元 探讨云库安全分享计划

在公司的开放式办公室中&#xff0c;卧龙与凤雏相邻而坐。周围的同事们都在忙碌地工作&#xff0c;键盘敲击声不绝于耳。卧龙眉头紧锁&#xff0c;全神贯注地调试着复杂的代码&#xff0c;仿佛在挑战编程世界的极限。而凤雏则在完成了一段代码编写后&#xff0c;轻松地伸展着身…

联丰策略股票官网分析A股三大指数集体收跌,超3800只股票下跌

查查配今日A股三大指数集体收跌。沪指低开低走,午后A股上了微博热搜。 联丰策略拥有一支由知名互联网公司和国内证券金融机构的行业专家组成的一流运营团队。凭借他们在互联网产品开发和金融风险管理方面的丰富经验,我们的团队致力于为客户提供专业和个性化的证券交易服务。 截…