[Linux]缓冲区的理解

news/2024/11/27 10:56:00/文章来源:https://www.cnblogs.com/wzhiheng/p/18571883

缓冲区的理解

先来看这段代码

#include <stdio.h>
#include <unistd.h>
#include <string.h>int main()
{//C接口printf("hello printf\n");fprintf(stdout, "hello fprintf\n");fputs("hello fputs\n", stdout);//系统接口const char* msg = "hello write\n";write(1, msg, strlen(msg));fork();//子进程什么都不做,只是创建出来然后关闭return 0;
}

同一个程序,为什么直接运行,和将运行结果重定向到文件中然后再输出的结果为什么不一样呢?让我们再把fork()这行注释后再看看。

此时,运行结果又相同了。这又是为什么呢?

缓冲区

我们所谈论的都是用户级缓冲区。

  1. 什么是缓冲区

    缓冲区本质就是一段内存,为了节省进程进行数据IO的时间。比如,CPU 和硬盘之间,硬盘的数据读取速度远远慢于 CPU 的处理速度。当从硬盘读取数据时,数据会先被读入缓冲区,然后 CPU 再从缓冲区获取数据进行处理,这样就可以避免 CPU 因为等待硬盘缓慢的数据读取而浪费时间。

  2. 缓冲区的刷新策略

    如果有一块数据,那么它是一次写入到外设中效率高,还是少量多次的写入到外设效率高呢?答案肯定是第一种情况。虽然这种效率最高,但是缓冲区会结合具体的设备,定制自己的刷新策略:

    • 立即刷新,也就是无缓冲。
    • 行刷新,对应行缓存,通常也是显示器的刷新策略。
    • 缓冲区满,对应全缓冲,通常也是磁盘文件的刷新刷新策略。

    还有两种特殊的刷新策略:

    • 用户强制刷新,比如使用fflush()函数。
    • 进程退出,一般都要进行缓冲区刷新。

现在我们再来解决上面的问题。我们发现只要是库函数都输出了两次,而系统调用只输出了一次,将fork()函数注释后就符合我们的预期了,那么这肯定和fork()有关。

  1. 一般C库函数写入文件时是全缓冲的,而写入显示器是行缓冲。如果没有进行重定向,stdout默认使用的是行刷新,进程在fork之前,三条C函数已经将数据进行打印输出到显示器上,此时缓冲区内部已经没有数据了。
  2. printf,fwrite等库函数会自带缓冲区,当发生重定向到普通文件时,数据的缓冲方式由行缓冲变成了全缓冲。此时数据不会立即刷新。
  3. 执行fork的时候,stdout属于父进程,创建子进程,由于子进程是以父进程为模板创建出来的。当子进程退出时,会修改缓冲区的数据发生写时拷贝。因此数据会有两份。
  4. write没有变化,说明write没有所谓的缓冲。

综上,printf,fwrite等库函数会自带缓冲区,而write系统调用没有带缓冲区。库函数在系统调用的”上层“,但是write没有缓冲区,而printf,fwrite等有,这足以说明这个缓冲区是由C标准库提供的。

FILE

  • 由于IO相关函数与系统调用接口对应,并且库函数是封装了系统调用,所以本质上,访问文件都是通过访问fd访问的。
  • 所以C语言的FILE结构体中肯定封装了fd。
  • 由于缓冲区是由C标准库提供,所以FILE结构体中肯定由缓冲区相关的内容。

FILE结构体

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

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

相关文章

Ollama本地部署Qwen2.5 14B(使用docker实现Nvidia GPU支持)

通过docker部署支持Nvidia GPU加速的本地大模型前提条件:已经本地安装好了Ollama。 如果没有安装Ollama或者想部署其他的模型或者不想使用docker,,可以参考之前的这篇文章: https://www.cnblogs.com/Chenlead/p/18571005 安装过程参考:https://docs.openwebui.com/getting…

Jmeter 临界部分控制器 Critical Section Controller

Jmeter必知利器-临界部分控制器-腾讯云开发者社区-腾讯云 Jmeter之临界部分控制器使用-CSDN博客 使用前,线程执行顺序随机 使用后,线程执行顺序从上到下

dedecms提示500错误解决方法

查看网站程序版本:打开 /data/admin/ver.txt 文件查看 查看主机PHP版本:在主机面板查看或创建一个 p.php 文件,内容为 <?php phpinfo(); ?>,上传到网站根目录,访问 http://域名/p.php 查看PHP版本,完成后删除 p.php 低版本织梦(2014、2015、2016、2017开头)无法…

自动检测工作人员工服穿戴规范行为

自动检测工作人员工服穿戴规范行为利用现场安装的高清摄像机,自动检测工作人员工服穿戴规范行为对采集到的视频进行预处理,识别出图像中的员工,并检测其工服穿戴情况,一旦系统判断出工服穿戴异常,将立即发出警报,通知管理人员或自动启动相应的安全措施。通过实时监测,及…

Docker Logs清理

查看docker日志路径 docker inspect --format={{.LogPath}} <container_name_or_id>清理docker日志 echo |sudo tee $(docker inspect --format={{.LogPath}} <container_name_or_id>).zstitle { width: 280px; text-align: center; font-size: 26px } .zsimgwei…

hhdb数据库介绍(9-9)

高可用服务 读写分离 计算节点支持读写分离功能,并且支持配置读写分离权重 读写分离功能说明 要使用读写分离功能,需在数据节点中配置主备存储节点。 读写分离功能默认设置为关闭。开启读写分离功能,可在计算节点的配置文件server.xml中,将strategyForRWSplit属性设置为大于…

调制与解调(AM和DSB)

调制 调制 调制大信号 小信号 小信号>100mV, <100mV <100mVAM 数学原理 开关函数 平方律弧度区器件形式 二极管(非环)↓ 三极管(基极集电极调幅)↓ 场效应管 差分放大器 二极管 三极管 场效应管(平方律器件)DSB 数学原理 开关函数 双曲正切->线性区器件形式 二极管…

编写bash脚本快速kill或启动tomcat

​假设tomcat安装路径为 /home/tomcat,示例如下: 1. kill tomcat进程 vim kill-tomcat-force.sh set fileformat=unix path=/home/tomcat/binecho"exec $path/shutdown.sh" $path/shutdown.shsleep3s#kill -9 pid ps -ef|grep $path|grep tomcat|awk {print $2}|xar…

网页本地预览正常, 上传服务器后乱码、错位是怎么回事

网站本地预览正常, 如果上传后出现错位和乱码, 大概率是css或者js没有正确引入导致的。 这种情况处理比较简单, 检查文件路径并修复即可。 但有一种特殊情况, 各种文件路径都对, 通过浏览器也可以正常访问, 但前端页面就是错位。 那你检查一下, 网页源代码中是否存在以…

问EBS R12中怎样实现输出格式是多sheet页excel报表,不用excel模板实现,而是在sqlplus中用xml或者html代码来实现

https://www.itpub.net/thread-2094848-1-1.html 来源手工创建一个EXCEL,放一些数据进去,然后另存为xml表格,用notepad打开看看,里面有代码。把代码用SQL拼接起来。<?xml version="1.0"?><?mso-application progid="Excel.Sheet"?>&l…

postman: 提交的文本中有+加号时在服务端变成了空格

一,现象:如果填写参数时使用的是params类型,而value中包含+,则此时的值在提交到线上时会被替换成空格,原因是:使用params类型参数和值会拼接在url中二,解决:在body标签下,使用form-data类型,此时的各项值不会被拼接到url中,+也就不会被替换成空格了

Zabbix 模板翻译自动化

在企业 IT 运维管理中,Zabbix 作为一款强大的开源监控平台被广泛应用。而 Zabbix 模板作为监控配置的重要组成部分,用来定义监控项、触发器、图形等。随着国际化的需求增加,Zabbix 模板的翻译工作变得日益重要,特别是在需要为不同语言环境下的运维团队提供支持时,手动翻译…