linux入门---缓冲区

news2025/3/1 22:02:47

查看问题

首先大家来看看下面这段代码

1 #include<stdio.h>
  2 #include<string.h>
  3 #include<unistd.h>
  4 int main()
  5 {
  6     printf("i am printf\n");
  7     fprintf(stdout,"i am fprintf\n");
  8     fputs("i am fputs\n",stdout);
  9     const char arr[]="i am write\n";                                                                                                
 10     write(1,arr,strlen(arr));
 11     return 0;
 12 }

这段代码通过四种不同的函数向屏幕上打印内容代码的运行结果如下:
在这里插入图片描述

没有意外这段代码将四行数据全部输出到了屏幕上,但是这里可以使用输出重定向将原本输出到屏幕上的数据输出到文件里面,比如说下面的操作:
在这里插入图片描述
文件里面的内容也没有啥问题数据也只输出了一遍,那这里我们对代码做一下修改,在代码的后面添加一个fork函数:

  1 #include<stdio.h>
  2 #include<string.h>
  3 #include<unistd.h>
  4 #include<fcntl.h>
  5 #include<sys/types.h>
  6 #include<sys/stat.h>
  7 int main()
  8 {
  9     int fd=open("mytest1",O_WRONLY|O_CREAT|O_TRUNC,"w");
 11     printf("i am printf\n");
 12     fprintf(stdout,"i am fprintf\n");
 13     fputs("i am fputs\n",stdout);
 14     const char arr[]="i am write\n";
 15     write(1,arr,strlen(arr));
 16     fork();                                                                                                                         
 17     close(fd);
 18     return 0;
 19 }

运行一下上面的代码就会发现这里也没有出现问题,因为fork函数执行前其他的打印函数已经执行完了,所以所以所有的内容只打印了一遍:
在这里插入图片描述
但是将上述代码重定向输出到另外一个文件的时候我们发现这里出问题了:
在这里插入图片描述
为什么printf fprintf fputs函数会多打印一份而write函数却只打印一遍呢?原因是和缓冲区有关,首先缓冲区本质上就是一段内存,那既然是内存的话就会存在两个问题1.这个内存是谁申请的? 2.这个内存有什么意义?我们先来讨论第二个问题。

缓冲区的意义

这里通过一个小故事来带着大家理解一下缓冲区的作用。张三和李四是一对关系非常好的朋友,但是两个人因为一些原因相距非常的远,张三住在西藏而李四住在上海,

在这里插入图片描述

李四的家境十分的阔绰所以每次都想送给张三一些好吃的好玩的比如说送给张三一个4090的显卡一个华硕的显示器等等等,突然有一天李四放暑假了准备专门用暑假的时间来把这些东西送给张三,李四打电话给张三说:张三啊!你现在是在西藏吧,我现在放暑假了这样好吧我准备了一些小礼物给你,我准备花一整个暑假的时间骑电动车亲自给你送过去,我到你家楼下了给你发个消息你记得给我开门哈我送完东西就走不打扰你正常生化的。张三一听傻眼了西藏和上海相距十万八千里,你要亲自给我送过来这得花多少时间啊而且李四平时的工作还非常的繁忙送来东西又不在西藏玩个几天送完就走,所以张三立马跟李四说:李四啊你这么繁忙你为什么要花这么多时间亲自给我送东西,你亲自送就算了你送来了也不在西藏多玩几天送完就走这多浪费你的时间和精力啊对吧,你直接把东西放到楼下的快递站,让快递小哥帮你送不就可以了吗?把节省下来的时间 我们拿去打打游戏写写代码不更好些吗?李四一想好像非常的有道理于是就将东西放到了楼下的快递站,

在这里插入图片描述

看到这里大家应该能够知道快递在社会中存在的意义,他可以节省发送者的时间,而上述故事中的上海就是电脑中的内存,西藏就是电脑的内存,李四就相当于内存中的进程,张三就相当于硬盘中的文件,而李四送给张三的礼物就相当于内存中的进程要向文件中写入的数据,把快递交给快递小哥就相当于把进程的数据拷贝到缓冲区里面,而这里的拷贝用到的就是fwrite函数,与其理解fwrite函数理解成写入到文件的函数,倒不如理解fwrite函数是拷贝函数,将数据从进程拷贝到缓冲区或者外设当中,帮李四送东西的快递小哥就相当于内存中的缓冲区,快递的意义是帮助发送者节约时间,那缓冲区中的意义就是提高进程进行数据IO的时间。
在这里插入图片描述

缓冲区刷新策略

这里继续通过上面的例子带着大家了解缓冲区的刷新策略,李四将东西交给了外卖小哥可是第二天李四在手机上查快递的情况是发现快递还没有发出就感到十分的生气,他立马打电话给快递员说:为什么快递还没有发出去呢?你们在干什么啊?这时快递员非常的恼火怼了一句,你以为你是谁啊?你刚给我我就得把快递给你送出去,你等着吧等我快递能够堆满一车我就给你送出去,那这里的堆满一车就是操作系统一个刷新缓冲区的策略,当缓冲区的空间装满数据之后操作系统就会刷新缓冲区将里面的数据发到指定位置,在外设当中磁盘就是采用这样的刷新策略。在快递当中也不是非得装满一车才能发货,比如说有一些vip客户的重要快递,这些人寄快递花了很多的钱所以他们的快递会发的比较快一些,因为有个大大的vip标志,那么对于这种特殊的标志操作系统也有一个对应的缓冲区刷新策略:行缓冲当缓冲区中遇到了\n字符时就会立马刷新缓冲区将数据传送到指定位置,电脑的显示屏采用的就是这样的刷新策略,这也是为什么之前打印数据的时候不加\n就显示不出来打印的内容,操作系统中还有一个刷新策略就是立即缓冲,只要我们往缓冲区里面输入了数据就会立刻刷新缓冲区,这就相当于我们亲自把物品送给一个人不需要等待快递,因为使用电脑的过程肯定存在要写入一些十分重要的信息的情况,而数据是存储在内存上的,内存的特点就是掉电易失,所以为了减少数据写入时的意外就有了这样的刷新策略。

缓冲区在哪

根据上面的代码的运行情况我们首先能够确定俩件事第一:之所以会出现这样的情况肯定和缓冲区有关,并且还和写时拷贝有关,第二:缓冲区一定不在内核当中因为printf,fprintf,fputs函数,这三个函数都属于c语言提供的函数,而write函数是操作系统提供的函数,如果缓冲区在内核当中的话write函数也会打印两次内容,所以我们之前谈论的所有缓冲区,都指的是用户级语言层面给我们提供的缓冲区,我们知道stdout,stdin,stderr以及我们用c语言打开文件都得创建一个FILE指针来指向新打开的文件,FILE是一个结构体而缓冲区就在FILE结构体里面,也就是FILE结构体里面不仅含有一个字段记录文件在操作系统中的fd还有一块空间作为缓冲区,所以我们平时使用fflush函数刷新缓冲区,使用fclose函数关闭文件时为什么要传一个FILE指针,原因就是刷新FILE结构体里面的缓冲区。

上述问题的解释

我们再来看看这段代码:

  1 #include<stdio.h>
  2 #include<string.h>
  3 #include<unistd.h>
  4 #include<fcntl.h>
  5 #include<sys/types.h>
  6 #include<sys/stat.h>
  7 int main()
  8 {
  9     int fd=open("mytest1",O_WRONLY|O_CREAT|O_TRUNC,"w");
 11     printf("i am printf\n");
 12     fprintf(stdout,"i am fprintf\n");
 13     fputs("i am fputs\n",stdout);
 14     const char arr[]="i am write\n";
 15     write(1,arr,strlen(arr));
 16     fork();                                                                                                                         
 17     close(fd);
 18     return 0;
 19 }

在代码结束之前会创建子进程。如果没有进行>看到的四条信息,因为stdout默认使用的是行刷新,在进程fork之前三条输出函数已经将数据进行打印输出到显示器上(外设),你的FILE内部也就是进程内部不存在要打印的数据,如果我们进行了输出重定向写入文件就不再是显示器而是普通文件,文件采用的刷新策略是全缓冲,在fork函数之前printf,fprintf,fputs函数想要输出一些数据,但是这些数据不足以让stdout缓冲区写满,所以数据并没有被刷新输出到屏幕上面,执行完fork函数父进程就要创建子进程紧接着就是父进程和子进程都要退出,谁先退出不知道,但是退出的时候一定会进行缓冲区刷新,而缓冲区是在FILE结构体上,FILE结构体又是属于子进程和父进程的,所以一旦退出就会发生写时拷贝数据会变成两份,所以文件里面就会出现两份printf,fprintf,fputs函数打印的内容,而write函数为什么没有显示两份的原因是:上面的过程都和write函数无关,write函数没有FILE,他是一个系统调用函数通过fd来向文件里面打印的内容,就没有c语言提供的缓冲区,在fork函数执行之前就已经将内容输出到屏幕上了不会发生写时拷贝,那这就是对代码的解释希望大家能够理解。

缓冲区和操作系统的关系

通过上面的介绍,当使用c语言的文件函数往硬盘上输出数据时这些数据会先存储到FILE结构体里面:
在这里插入图片描述
我们知道c语言文件函数是基于操作系统提供的接口实现的,也就是说这里想将数据输出到磁盘上就得使用操作系统提供的write函数,但是这里的数据也不是一下子就通过write函数刷新到磁盘上,而是先将数据拷贝到内核结构体file里面的缓冲区中
在这里插入图片描述
等数据来到内核的缓冲区中就会由操作系统决定什么时候将数据刷新到磁盘中,这里的刷新规则就十分的复杂并不是我们之前说的全缓冲和行缓冲无缓冲那么,这些刷新策略是c语言提供的,而操作系统刷新缓冲区得权衡一下利弊再做出对应的决定,比如说隔一段时间将内核缓冲区的数据刷新到磁盘上,当内存不够时时将数据刷新指定位置上等等,所以大家在写代码刷新缓冲区时自认为调用fflush函数将缓冲区清空了,实际上这个清空的是语言层面上的缓冲区而不是内核中的缓冲区,这一点大家要知道。
在这里插入图片描述
以上就是本篇文章的内容希望大家能够理解。

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

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

相关文章

Unity --- 物理引擎 --- 触发器 与 碰撞器详解

碰撞器补充讲解 对第一个条件进行补充 --- 不仅要两者都具有碰撞组件&#xff0c;同时还需要两者的碰撞组件中都没有勾选 Is Trigger属性 1.上一篇文章中说了那么多&#xff0c;其实也可以总结为两个碰撞条件 --- a.两个游戏物体都具有碰撞器组件 &#xff0c;如果没有的话&…

【数据结构】哈希表详解以及代码实现

目录 1.来源&#xff1a; 2.哈希函数 1.哈希函数的设计规则 2.哈希函数的设计思路 3.哈希碰撞 4.解决哈希碰撞的方案 5.负载因子 3.基于开散列方案的HashMap实现 1.HashMap类中的属性 2.哈希函数 3.判断当前哈希表中是否含有指定的key值 4.判断当前哈希表中是否包含…

【尊享版】聊聊我最近比较重要的一些认知升级

超友们&#xff0c;早上好&#xff5e; 今天我为你带来的分享是《聊聊我最近比较重要的一些认知升级》&#xff0c;主要分为三个部分&#xff1a; 一、【10 点战略认知升级】 二、【10 点学习认知升级】 三、【5 点提效认知升级】 &#x1f388;一、【10 点战略认知升级】 …

基于Java+SpringBoot+vue的在线动漫信息平台设计与实现【源码(完整源码请私聊)+论文+演示视频+包运行成功】

博主介绍&#xff1a;专注于Java技术领域和毕业项目实战 &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447;&#x1f3fb; 不然下次找不到哟 Java项目精品实战案例&#xff08;300套&#xff09; 目录 一、效果演示 二、…

一文吃透泛型

本文已经收录到Github仓库&#xff0c;该仓库包含计算机基础、Java基础、多线程、JVM、数据库、Redis、Spring、Mybatis、SpringMVC、SpringBoot、分布式、微服务、设计模式、架构、校招社招分享等核心知识点&#xff0c;欢迎star~ Github地址 如果访问不了Github&#xff0c…

CVE-2017-10271 WebLogic XMLDecoder反序列化漏洞

靶场环境&#xff1a;vulnstack靶机-委派靶场 漏洞描述 CVE-2017-10271漏洞产生的原因大致是Weblogic的WLS Security组件对外提供webservice服务&#xff0c;其中使用了XMLDecoder来解析用户传入的XML数据&#xff0c;在解析的过程中出现反序列化漏洞&#xff0c;导致可执行任…

【RabbitMQ】Spring整合RabbitMQ、Spring实现RabbitMQ五大工作模式(万字长文)

目录 一、准备 1、创建maven项目​编辑 2、引入依赖 3、创建配置文件 1.RabbitMQ配置文件 2.生产者项目配置文件 3.消费者项目配置文件 二、生产者xml中文件创建队列 三、生产者xml文件中创建交换机以及绑定队列 1、创建交换机 2、绑定队列 四、消费者xml文件中创建…

第五十八章 线段树(一)

第五十八章 线段树&#xff08;一&#xff09;一、树状数组的缺陷二、线段树的作用三、线段树的基本构成1、节点定义2、线段树的结构四、线段树的重要函数1、构造线段树——bulid函数2、查询区间——query函数3、单点修改——modify函数五、例题一、树状数组的缺陷 在前面两个…

flink 的 State

目录 一、前言 二、什么是State 2.1&#xff1a;什么时候需要历史数据 2.2&#xff1a;为什么要容错&#xff0c;以及checkpoint如何进行容错 2.3&#xff1a;state basckend 又是什么 三、有哪些常见的是 State 四、 State的使用 五、State backend 5.1 MemoryState…

进程,线程,调度和调度算法基本知识

进程 我们编写的代码只是一个存储在硬盘的静态文件&#xff0c;通过编译后就会生成二进制可执行文件&#xff0c;当我们运行这个可执行文件后&#xff0c;它会被装载到内存中&#xff0c;接着 CPU 会执行程序中的每一条指令&#xff0c;那么这个运行中的程序&#xff0c;就被称…

【C++】内联函数理解

内联函数 内联函数的使用是对于C语言中宏函数的一种改进&#xff0c;他继承了宏的优点并避免了宏的缺点。 宏的优点&#xff1a;a. 代码复用性高 b. 宏函数减少栈帧建立&#xff0c;提高效率 宏的缺点&#xff1a;a. 可读性差 b. 没有类型安全检查 c. 不方便调试 C基本不再建议…

银行数字化转型导师坚鹏:金融数据治理、数据安全政策解读

金融数据治理、数据安全政策解读及大数据应用课程背景&#xff1a; 很多银行存在以下问题&#xff1a; 不知道如何准确理解金融数据治理及数据安全相关政策 不清楚金融数据治理及数据安全相关政策对银行有什么影响&#xff1f; 不清楚如何有效应用金融数据治理及数据安全相关…

软考软件设计师 下午试题二笔记

E-R图基本图形元素 实体 一个实体的存在要以另一个实体存在为前提&#xff0c;这个就是弱实体&#xff0c;比如家属和职工&#xff0c;家属的存在就是依赖于职工 属性 属性带下划线的是主键 联系 三个实体之间的联系 试题二问题一例题 问题二 将er图转成关系模式就是问题二答…

Cell Discovery:人类特异基因促进大脑皮层折叠新机制

在人类进化过程中&#xff0c;新皮层的扩张与智力的提高和认知功能的改善密切相关。这种扩张的一个关键方面是大脑皮层沟回的形成&#xff0c;它使扩张的皮质表面积能够适应有限的颅骨空间。这些进化特征主要依赖于多种神经干细胞和祖细胞亚型及其神经源性分裂产生的更多数量的…

《计算机网络-自顶向下》05. 网络层-控制平面

文章目录路由控制方式每路由控制逻辑集中式控制路由选择算法LS —— 链路状态路由选择算法DV —— 距离向量路由选择算法LS 和 DV 算法的比较自治系统内部路由协议RIPOSPF自治系统外部路由协议&#xff1a;BGP通告 BGP 路由信息选择最好的路由相关术语热土豆选择路由选择算法&a…

Swagger教程

Swagger 目标 Swagger简介【了解】 Springboot整合swagger【掌握】 Swagger 常用注解【掌握】 一、Swagger简介 ​ Swagger 是一系列 RESTful API 的工具&#xff0c;通过 Swagger 可以获得项目的⼀种交互式文档&#xff0c;客户端 SDK 的自 动生成等功能。 ​ Swagger …

TryHackMe-Year of the Owl(Windows渗透测试)

Year of the Owl 当迷宫在你面前&#xff0c;你迷失了方向时&#xff0c;有时跳墙思考是前进的方向。 端口扫描 循例 nmap SMB枚举 smbmap enum4linux也什么都没有 Web枚举 80端口 gobuster扫到一堆403&#xff0c;并没有什么有用的信息 443端口与80端口一致 47001端口依…

【SQL】公网远程访问局域网SQL Server数据库【无公网IP内网穿透】

目录 1.前言 2.本地安装和设置SQL Server 2.1 SQL Server下载 2.2 SQL Server本地连接测试 2.3 Cpolar内网穿透的下载和安装 2.3 Cpolar内网穿透的注册 3.1 Cpolar云端设置 3.2 Cpolar本地设置 4.公网访问测试 5.结语 转发自CSDN远程穿透的文章&#xff1a;[无需公网IP&am…

详解以太坊

以太坊原理 以太坊通过建立终极的抽象的基础层-内置有图灵完备编程语言的区块链-使得任何人都能够创建合约和去中心化应用&#xff0c;并在其中设立他们自由定义的所有权规则、交易方式和状态转换函数。 图灵完备&#xff1a;能够运行非常复杂的运算&#xff0c;最简单的理解…

基于共享储能电站的工业用户日前优化经济调度

目录 1 主要内容 共享电站示意图 目标函数 2 部分程序 3 程序结果 4 程序链接 1 主要内容 该程序方法复现《基于共享储能电站的工业用户日前优化经济调度》算例2和算例3&#xff0c;根据共享储能电站的商业运营模式&#xff0c;将共享储能电站应用到工业用户经济优化调度…