Linux笔记---缓冲区

1. 什么是缓冲区

在计算机系统中,缓冲区(Buffer) 是一种临时存储数据的区域,主要用于协调不同速度或不同时序的组件之间的数据传输,以提高效率并减少资源冲突。它是系统设计中的重要概念,尤其在I/O操作、网络通信、硬件交互等领域广泛应用。

引入缓冲区机制有以下几方面的意义:

提高数据传输效率

  • 减少数据传输次数:缓冲区可以暂存数据,当数据量达到一定程度时再进行一次性传输,从而减少了频繁的数据传输次数,提高了传输效率。

  • 平衡数据传输速度差异:在不同设备或模块之间进行数据传输时,它们的数据传输速度可能不同。缓冲区可以作为一个中间存储区域,用来平衡这种速度差异,避免数据丢失或传输错误。

增强系统稳定性和可靠性

  • 防止数据丢失:在数据传输过程中,如果接收方不能及时处理数据,缓冲区可以暂时存储这些数据,直到接收方有能力处理为止,从而防止数据丢失。

  • 提供错误处理机制:缓冲区可以在数据传输过程中对数据进行校验和错误检测,当发现错误时,可以采取相应的措施进行纠正或重传,从而提高数据传输的可靠性。

优化系统资源利用

  • 提高CPU利用率:通过使用缓冲区,CPU可以在数据传输的同时进行其他操作,而不必等待数据传输完成,从而提高了CPU的利用率。

  • 合理利用内存资源:缓冲区可以根据实际需要动态分配内存,避免了因数据传输而频繁申请和释放内存,提高了内存的利用率。

支持异步操作

  • 实现异步数据传输:缓冲区可以支持异步数据传输,即发送方可以在不等待接收方响应的情况下继续执行其他操作,从而提高了系统的并发处理能力。

  • 提高系统响应速度:在异步操作中,缓冲区可以暂存请求或响应数据,使得系统能够更快地响应用户的操作,提高了系统的响应速度。

举例来说,菜鸟驿站实际上就是快递系统地一个缓冲区。

快递员要负责配送许多用户的快递,但是等待用户一个一个地来取无疑浪费了快递员的时间,降低了其工作效率。而菜鸟驿站的设立使得快递员直接将数据交付到站点即可离开配送下一个快递。

买家有多件快递,每一个快递被送到之后都需要其下楼来与快递员交互。而菜鸟驿站使得买家可以在所有的快递全部到达之后再一次性取走,减少了跑路的次数,节省了时间。

菜鸟驿站在入库快递时,相当于是对包裹又进行了一次清点。

同时,如果在快递到达之后买家有事无法在短时间内取得,则快递可以被寄放在菜鸟驿站,避免丢失。

2. 缓冲类型

什么情况下会刷新缓冲区,进行系统调用操作呢?

标准I/O提供了3种类型的缓冲区:

  • 全缓冲区:这种缓冲方式要求填满整个缓冲区后才进行I/O系统调用操作。对于磁盘文件的操作通常使用全缓冲的方式访问。

  • 行缓冲区:在行缓冲情况下,当在输入和输出中遇到换行符时,标准I/O库函数将会执行系统调用操作。当所操作的流涉及一个终端时(例如标准输入和标准输出),使用行缓冲方式。因为标准I/O库每行的缓冲区长度是固定的,所以只要填满了缓冲区,即使还没有遇到换行符,也会执行I/O系统调用操作,默认行缓冲区的大小为1024。

  • 无缓冲区:无缓冲区是指标准I/O库不对字符进行缓存,直接调用系统调用。标准错误流stderr通常是不带缓冲区的,这使得出错信息能够尽快地显示出来。

除了上述列举的默认刷新方式,下列特殊情况也会引发缓冲区的刷新:

  • 缓冲区满时。

  • 执行flush语句时。

  • 程序退出时。

#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>int main() {close(1);int fd = open("log.txt", O_WRONLY | O_CREAT | O_TRUNC, 0666);if (fd < 0) {perror("open");return 0;} printf("hello world: %d\n", fd);close(fd);return 0;
}

根据我们之前学的知识," hello world:1\n " 应该被写入文件 log.txt 中。然而实际上却并没有:

这是因为:(1) 我们将1号描述符重定向到磁盘文件后,缓冲区的刷新方式成为了全缓冲;(2) 被写入文件的数据会经过两个缓冲区,语言层缓冲区和Linux内核缓冲区;(3) 数据一旦到达Linux内核缓冲区就一定会被正确写入文件;(4) printf被调用后," hello world:1\n " 首先以全缓冲方式被存放在语言层的缓冲区,由于数据较少缓冲区未刷新;(5) 当程序退出时,语言层的缓冲区会尝试刷新,但此时 log.txt 已将被关闭了,所以 " hello world:1\n " 未被写入。

遇到这种情况,我们可以在文件关闭之前使用 fflush 函数来强制刷新缓冲区:

#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>int main() {close(1);int fd = open("log.txt", O_WRONLY | O_CREAT | O_TRUNC, 0666);if (fd < 0) {perror("open");return 0;} printf("hello world: %d\n", fd);fflush(stdout);close(fd);return 0;
}

3. 语言缓冲区

C语言提供的读写函数,实际上是对系统调用 read 和 write 进行了封装,并加上了一层额外的语言层的缓冲区。read 和 write 本身是没有缓冲区的,在进行数据读出和写入时,二者直接与内核缓冲区进行交互。

我们可以来验证这一点:

#include <stdio.h>
#include <string.h>int main()
{const char* msg0 = "hello printf\n";const char* msg1 = "hello fwrite\n";const char* msg2 = "hello write\n";printf("%s", msg0);fwrite(msg1, strlen(msg0), 1, stdout);write(1, msg2, strlen(msg2));fork();return 0;
}

运行结果:

hello printf
hello fwrite
hello write

但如果在运行时进行重定向的话(./test > log.txt):

hello write
hello printf
hello fwrite
hello printf
hello fwrite

进行重定向之后,刷新方式变为全刷新。write 函数直接将数据写入内核缓冲区中,所以不受影响;但是 printf 和 fwrite 写入的数据会先被存放在语言层缓冲区中,等到进程退出时再写入。

在 fork 函数执行之后,语言层缓冲区的数据被复制给了子进程,所以在进程退出时,父子进程先后将自身的缓冲区刷新,导致 printf 和 fwrite 写入的数据被写了两次。

语言级缓冲区实际上存在于 FILE 结构体中,与 printf 封装 write 类似,FILE结构体 封装了 struct file 结构体,并用一个字段来作为缓冲区。

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

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

相关文章

Tomcat基础知识及其配置

1.Tomcat简介 Tomcat是Apache软件基金会&#xff08;Apache Software Foundation&#xff09;的Jakarta 项目中的一个核心项目&#xff0c;由Apache、Sun和其他一些公司及个人共同开发而成。 Tomcat服务器是一个免费的开放源代码的Web应用服务器&#xff0c;属于轻量级应用服…

机器学习数学通关指南

✨ 写在前面 &#x1f4a1; 在代码的世界里沉浸了十余载&#xff0c;我一直自诩逻辑思维敏捷&#xff0c;编程能力不俗。然而&#xff0c;当我初次接触 DeepSeek-R1 并领略其清晰、系统的思考过程时&#xff0c;我不禁为之震撼。那一刻&#xff0c;我深刻意识到&#xff1a;在A…

数据结构之八大排序算法详解

目录 一、冒泡排序&#xff08;Bubble Sort&#xff09;原理代码实现时间复杂度 二、选择排序&#xff08;Selection Sort&#xff09;原理代码实现时间复杂度 三、插入排序&#xff08;Insertion Sort&#xff09;原理代码实现时间复杂度 四、希尔排序&#xff08;Shell Sort&…

RocketMQ的运行架构

目录 1. 核心组件(1) NameServer(2) Broker(3) Producer(4) Consumer 2. 消息流转流程3. 高可用机制4. 扩展性与负载均衡5.容错机制5. 特殊功能支持6. 典型部署架构总结 RocketMQ 是一款高性能、高可靠的分布式消息中间件&#xff0c;其运行架构设计为分布式、可扩展、高可用的…

【AIGC系列】5:视频生成模型数据处理和预训练流程介绍(Sora、MovieGen、HunyuanVideo)

AIGC系列博文&#xff1a; 【AIGC系列】1&#xff1a;自编码器&#xff08;AutoEncoder, AE&#xff09; 【AIGC系列】2&#xff1a;DALLE 2模型介绍&#xff08;内含扩散模型介绍&#xff09; 【AIGC系列】3&#xff1a;Stable Diffusion模型原理介绍 【AIGC系列】4&#xff1…

算法日记32:15届蓝桥C++B填空(握手问题+小球反弹)

握手问题 一、题解 1、通过观察我们可以发现&#xff0c;题目属于数论中的蜂巢问题&#xff0c;但是我们这里不使用结论&#xff0c;而是通过分析推出 2、假设我们不考虑特殊情况(也就是那 7 7 7个人的情况)&#xff0c;那么问题的答案应该为 int res0; for(int i49;i>1;i…

【三维分割】LangSplat: 3D Language Gaussian Splatting(CVPR 2024 highlight)

论文&#xff1a;https://arxiv.org/pdf/2312.16084 代码&#xff1a;https://github.com/minghanqin/LangSplat 文章目录 一、3D language field二、回顾 Language Fields的挑战三、使用SAM学习层次结构语义四、Language Fields 的 3DGS五、开放词汇查询&#xff08;Open-voca…

Windows安装sql server2017

看了下官网的文档&#xff0c;似乎只有ubuntu18.04可以安装&#xff0c;其他debian系的都不行&#xff0c;还有通过docker的方式安装的。 双击进入下载的ISO&#xff0c;点击执行可执行文件&#xff0c;并选择“是” 不要勾选 警告而已&#xff0c;不必理会 至少勾选这两…

LabVIEW图像识别抗干扰分析

问题描述 在基于LabVIEW的探针定位系统中&#xff0c;存在两个核心技术难点&#xff1a; 相机畸变导致初始定位误差&#xff1a;非线性畸变使探针无法通过坐标变换直接精确定位&#xff0c;需采用粗定位图像修正的两段式控制策略。 图像识别可靠性不足&#xff1a;复杂背景&a…

Leetcode1 两数之和 python两种方法实现

Leetcode1 两数之和 python两种方法实现 文章目录 Leetcode1 两数之和 python两种方法实现方法一&#xff1a;枚举法&#xff08;暴力解法&#xff09;方法二&#xff1a;用空间换时间。 给定一个整数数组 nums 和一个整数目标值 target&#xff0c;请你在该数组中找出 和为…

总结前端常用数据结构 之 队列篇【JavaScript 】

推动你的事业&#xff0c;不要让你的事业推动你。——爱因斯坦 目录 队列是什么&#xff1f;JS异步、事件循环、任务队列&#xff1a;队列的实现方法&#xff1a;‌数组实现‌ - 封装队列&#xff1a;对象实现&#xff08;优化性能&#xff09;- 封装队列&#xff1a; 队列应用…

C# 数据转换

1. 文本框读取byte&#xff0c;ushort格式数据 byte addr; if (byte.TryParse(textBoxAddr.Text, out addr) true) {}2. 字节数组 (byte[]) 转换为 ASCII 字符串 byte[] bytes { 72, 101, 108, 108, 111 }; // "Hello" 的 ASCII 码 string s0 Encoding.ASCII.Ge…

golang部分语法介绍(range关键字,函数定义+特性,结构体初始化+结构体指针/方法)

目录 golang语法 range关键字 介绍 使用 原理 函数 介绍 定义 特性 结构体 介绍 初始化 结构体指针 结构体方法 方法接收者 golang语法 range关键字 介绍 用于遍历数组&#xff08;array&#xff09;、切片&#xff08;slice&#xff09;、映射&#xff08;ma…

Linux与UDP应用1:翻译软件

UDP应用1&#xff1a;翻译软件 本篇介绍 本篇基于UDP编程接口基本使用中封装的服务器和客户端进行改写&#xff0c;基本功能如下&#xff1a; 从配置文件dict.txt读取到所有的单词和意思客户端向服务端发送英文服务端向客户端发送英文对应的中文意思 配置文件内容 下面的内…

【机器学习】逻辑回归(Logistic Regression)

逻辑回归 逻辑回归逻辑回归的流程Sigmoid函数Sigmoid函数的公式及图像 逻辑回归的损失函数与最优化求解逻辑回归使用梯度下降法求解 逻辑回归 逻辑回归与线性回归都是线性模型&#xff0c;其中线性回归使用线性式来预测数值&#xff0c;逻辑回归使用线性式来进行分类任务。 逻…

IDEA - 查看类的继承结构(通过快捷键查看、通过生成类图查看)

一、通过快捷键查看 在项目中定位到目标类&#xff08;例如&#xff0c;Executor.java&#xff09; 按下快捷键 【Ctrl H】 此时会弹出 Type Hierarchy 窗口&#xff0c;展示所有相关的父类、子类、接口 二、通过生成类图查看 在项目中定位到目标类&#xff08;例如&#x…

Leetcode-1776. Car Fleet II [C++][Java]

目录 一、题目描述 二、解题思路 【C】 【Java】 Leetcode-1776. Car Fleet IIhttps://leetcode.com/problems/car-fleet-ii/description/ 一、题目描述 There are n cars traveling at different speeds in the same direction along a one-lane road. You are given an …

《Python实战进阶》No 9:使用 Celery 实现异步任务队列

第9集&#xff1a;使用 Celery 实现异步任务队列 引言 在现代 Web 应用中&#xff0c;许多操作&#xff08;如发送邮件、处理文件上传、执行复杂计算等&#xff09;可能需要耗费较长时间。如果这些操作直接在主线程中执行&#xff0c;会导致用户请求阻塞&#xff0c;降低用户体…

ue5 创建多列StreeView的方法与理解

创建StreeView的多列样式怎么就像是创建单行单列差不多?貌似就是在单行单列中加入了多列widget? 目录结构: 必备条件 StreeView的多列创建需要的必备条件: 数据基类 CustomItemBase #pragma once /* ---------------------------------- | Name | Value …

Spring的下载与配置

1. 下载spring开发包 下载地址&#xff1a;https://repo.spring.io/webapp/#/artifacts/browse/simple/General/libs-release-local/org/springframework/spring 打开之后可以看到有很多版本供选择&#xff0c;因为视频教程用的是4.2.4版本&#xff0c;于是我也选择这个 右键…