【Linux后端服务器开发】缓冲区

news2024/11/30 0:42:21

目录

一、缓冲区概述

二、语言层面缓冲区

三、C语言模拟实现stdio库


一、缓冲区概述

Linux缓冲区是指在内存中开辟的一块区域,用于存储输入输出数据的临时存储区域。

当应用程序向文件或设备进行读写操作时,数据会先被存储到缓冲区中,然后再由缓冲区将数据写入磁盘或设备中。

缓冲区的作用是提高数据读写的效率,减少磁盘或设备的访问次数,从而提高系统的性能。

在Linux系统中,缓冲区的大小可以通过修改内核参数来进行调整。

缓冲区的作用:

  • 解放使用缓冲区的进程的时间(将数据放到缓冲区后,进程继续执行自己的代码)

  • 缓冲区的存在可以集中处理数据刷新,减少I/O的次数,从而达到提高整机的效率!

在这里插入图片描述

 

二、语言层面缓冲区

缓冲区:节省数据进行IO的时间

缓冲区会结合具体的设备,定制自己的刷新策略

  • 立即刷新 ---> 无缓冲
  • 行刷新 ---> 行缓冲 ---> 显示器
  • 缓冲区满 ---> 全缓冲 ---> 磁盘

缓冲区是用户语言层面给我们提供的,在FILE结构体里面

fflush()、close()可强制刷新缓冲区

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>

int main() 
{
    //C语言接口
    printf("hello printf\n");
    fprintf(stdout, "hello fprintf\n");
    fputs("hello fputs\n", stdout);

    //系统接口
    const char* agm = "hello write\n";
    write(1, agm, strlen(agm));

    fork();

    return 0;       
}

若未使用 > ,打印了四条字符串

  • stdout默认使用的是行刷新,在进程fork之前,三条C语言函数已经将数据打印输出到显示器(外设)上
  • 此时在FILE内部/进程内部不存在对应的数据了

若使用了 > ,打印了七条字符串

  • 写入文件不再是显示器而是普通文件,采用的刷新策略是全缓冲,之前三条C语言显示函数,虽然带了'\n',但是stdout缓冲区并没有刷新
  • 执行fork的时候,stdout属于父进程,创建子进程后进程退出,无论谁退出,退出时都会显示缓冲区刷新
  • 写时拷贝,数据最终会显示两份
  • write没有FILE,而是使用fd,没有C语言提供的缓冲区

三、C语言模拟实现stdio库

mystdio.h

#include <sys/types.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
#include <assert.h>

#define CAPACITY 1024
#define SYNC_NOW 1
#define SYNC_LINE 2
#define SYNC_FULL 3

typedef struct _FILE 
{
    int flags;
    int fileno;
    int cap;    //buffer的总容量
    int size;   //buffer的使用量
    char buffer[CAPACITY];  //文件缓冲区
}_FILE;

_FILE* _fopen(const char* path, const char* mode);

void _fwrite(const void* ptr, int num, _FILE* pf);

void _fflush(_FILE* pf);

void _fclose(_FILE* pf);

mystdio.c

#include "mystdio.h"

_FILE* _fopen(const char* path, const char* mode) 
{
    //标志位传参
    int flags = 0;
    if (strcmp(mode, "r") == 0) 
        flags |= O_RDONLY;
    else if (strcmp(mode, "w") == 0) 
        flags |= O_WRONLY | O_CREAT | O_TRUNC;
    else if (strcmp(mode, "a") == 0) 
        flags |= O_WRONLY | O_CREAT | O_APPEND;
    else 
        exit(1);

    umask(0);
    int defaultMode = 0666;
    int fd = 0;
    if (flags & O_RDONLY) 
        fd = open(path, flags);
    else 
        fd = open(path, flags, defaultMode);

    _FILE* pf = (_FILE*)malloc(sizeof(_FILE));
    assert(pf);
    pf->flags = SYNC_LINE;
    pf->fileno = fd;
    pf->cap = CAPACITY;
    pf->size = 0;
    memset(pf->buffer, 0, CAPACITY);
    return pf;
}

void _fwrite(const void* ptr, int num, _FILE* pf) 
{
    memcpy(pf->buffer + pf->size, ptr, num);
    pf->size += num;
    if (pf->flags & SYNC_NOW) 
    {
        write(pf->fileno, pf->buffer, pf->size);
        pf->size = 0;
    }
    else if (pf->flags & SYNC_FULL) 
    {
        if (pf->size == pf->cap) 
        {
            write(pf->fileno, pf->buffer, pf->size);
            pf->size = 0;
        }
    }
    else 
    {
        if (pf->buffer[pf->size - 1] == '\n') 
        {
            write(pf->fileno, pf->buffer, pf->size);
            pf->size = 0;
        }
    }
}

void _fflush(_FILE* pf) 
{
    if (pf->size > 0) 
        write(pf->fileno, pf->buffer, pf->size);
    fsync(pf->fileno);  //强制要求操作系统对外设进行数据刷新
    pf->size = 0;
}

void _fclose(_FILE* pf) 
{
    _fflush(pf);
    close(pf->fileno);
}

main.c

#include "mystdio.h"
#include <stdio.h>

int main() 
{
    //_FILE* pf = _fopen("test.txt", "w");
    _FILE* pf = _fopen("test.txt", "r");
    assert(pf);

    //写/追加
    // const char* msg = "hello world\n";
    // int cnt = 5;
    // while (cnt--) 
    // {
    //     printf("%d\n", cnt);
    //     _fwrite(msg, strlen(msg), pf);
    //     if (cnt == 5) 
    //         _fflush(pf);
    //     sleep(1);
    // }

    //读
    char* buffer[1024];
    read(pf->fileno, buffer, 1024);
    printf("%s\n", buffer);

    return 0;
}

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

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

相关文章

MYSQL学习第一天

1.创建数据库&#xff0c;删除数据库&#xff0c;查询创建数据的语句&#xff0c;使用数据库&#xff0c;查询当前默认的数据库以及使用的编码方式校验规则 1.1 创建数据库 create database db_name; 1.2 使用数据库 use db_name; 1.3 查询当前使用的数据库 select datab…

学校公寓管理系统

学校公寓管理系统是学校管理的重要组成部分&#xff0c;它的主要任务是通过数字化和自动化的方式提高公寓管理的效率&#xff0c;同时为学生提供更优质的服务。这个系统能够处理学生住宿的申请、房间的分配、住宿费用的收取以及公寓设施的使用等各项工作。 首先&#xff0c;学校…

【MR设备】燧光MR设备极简教程(使用篇)

燧光MR设备极简教程(使用篇) 一、硬件的基础使用二、定位信标三、投屏直播1、第三人称视角同步MR2、第一人称视角无线投屏相关文章:燧光MR设备极简教程(开发篇) 一、硬件的基础使用 官方使用文档:https://developer.ximmerse.com/#/example?id=6 1. 开机: 长按Home…

漫谈大数据时代的个人信息安全(一)——“按图索骥”

大数据时代的个人信息安全系列——“按图索骥” 一、寻找王珞丹二、啥是Exif &#xff1f;三、个人信息保护小贴士 近日&#xff0c;某高校毕业生在校期间窃取学校内网数据&#xff0c;收集全校学生个人隐私信息的新闻引发了人们对大数据时代个人信息安全问题的再度关注。在大数…

今日教会你录播课实时翻译怎么弄

在数字时代的浪潮中&#xff0c;视频教学是一种重要的教学方式。无论在网络教学平台&#xff0c;还是在大学教育或公司的培训中&#xff0c;录制课程都以其灵活、方便的特点&#xff0c;给广大师生提供了极大的便利。但是&#xff0c;随着国际间交往的不断深入&#xff0c;语言…

【第七章】习题

1、 下列代码创建了几个对象 public class stringPool {public static void main(String[] args) {String s1 new String("abc");String s2 new String("abc");if (s1 s2) {System.out.println("在堆中只创建了一个对象");} else {System.out…

(vue)整个页面添加背景视频

(vue)整个页面添加背景视频 App.vue <template><div id"app" :class"[platform]"><video src"./assets/images/top/bg-video-711.mp4" autoplay muted loop class"bg"></video><router-view /></di…

智能优化算法——灰狼优化算法(PythonMatlab实现)

目录 1 灰狼优化算法基本思想 2 灰狼捕食猎物过程 2.1 社会等级分层 2.2 包围猎物 2.3 狩猎 2.4 攻击猎物 2.5 寻找猎物 3 实现步骤及程序框图 3.1 步骤 3.2 程序框图 4 Python代码实现 5 Matlab实现 1 灰狼优化算法基本思想 灰狼优化算法是一种群智能优化算法&#xff0c;它的…

JAVA8 实体类集合多个字段组合排序

实体类集合多个字段组合排序&#xff0c;自由组合升降序&#xff0c;下面是参考代码示例&#xff1a; import lombok.Data;Data public class DbjrdmxDTO {private String djbh;private String rq; //订单日期private String ckdm;private String ckmc;private String newKhSig…

Coggle 30 Days of ML(23年7月)任务九:学会Bert基础,transformer库基础使用

Coggle 30 Days of ML&#xff08;23年7月&#xff09;任务九&#xff1a;学会Bert基础&#xff0c;transformer库基础使用 任务九&#xff1a;学会Bert基础&#xff0c;transformer库基础使用 说明&#xff1a;在这个任务中&#xff0c;你将学习Bert模型的基础知识&#xff…

【使用字符串转换时间问题?】Tue Jul 11 23:59:59 CST 2023

问题展示&#xff1a;想要去除多余显示只显示&#xff08;时分秒&#xff1a;23:59:59&#xff09; 解决办法&#xff1a; 问题解决 实现代码&#xff1a; String dateString "2023-07-11 23:59:59";SimpleDateFormat inputFormat new SimpleDateFormat("…

异常处理一例

1.现象 代码片段&#xff1a; uint8_t CmdListener(char c) { #define CMD_SIZE 5static uint8_t cmdQueue[9];static uint8_t cmdReset[] { !, b, o, o, t};static uint8_t cmdYModem[] { 0x01, 0x00, 0xff };static uint8_t cmdIdx 0;int i;xlog("%c", 0xcc);…

【LeetCode】HOT 100(27)

题单介绍&#xff1a; 精选 100 道力扣&#xff08;LeetCode&#xff09;上最热门的题目&#xff0c;适合初识算法与数据结构的新手和想要在短时间内高效提升的人&#xff0c;熟练掌握这 100 道题&#xff0c;你就已经具备了在代码世界通行的基本能力。 目录 题单介绍&#…

【Linux】ELK 企业级日志分析系统

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 ELK 企业级日志分析系统 ELK 概述1、ELK 简介2、为什么要使用 ELK3、完整日志系统基本特征4、ELK 的工作原理 ELK Elasticsearch 集群部署&#xff08;在Node1、Node2节点上操…

stm32(串口知识点)

HAL串口发送/接收函数&#xff1a; HAL_UART_Transmit(); 串口发送数据&#xff0c;使用超时管理机制HAL_UART_Receive(); 串口接收数据&#xff0c;使用超时管理机制HAL_UART_Transmit_IT(); 串口中断模式发送 HAL_UART_Receive_IT(); 串口中断模式接收 HAL_UART_Transmit(…

ByteBuddy学习笔记

ByteBuddy 1.ByteBuddy的用途 ByteBuddy通过修改字节码来新增、修改、删除Java类的现有功能&#xff0c;主要用于分离功能代码和非功能代码&#xff0c;比如 比如非功能代码如下&#xff1a; public double calculatePrice(){double discount getDiscount();double price …

【python手写算法】利用梯度下降实现线性拟合

利用梯度下降实现线性拟合&#xff0c;效果和sklearn LinearRegression()差不多。 学习率初始设置为0.1结果算高的&#xff0c;直接让我的参数变成了nan。&#xff08;体会到了飞出去的感觉&#xff09; 把学习率调小了之后就正常了 # codingutf-8 import matplotlib.pyplot a…

Android多渠道打包及资源指定

多渠道打包及资源指定 由于项目涉及多个车型&#xff0c;使用的是同一个base代码&#xff0c;不同车型都有差分项&#xff0c;所以需要进行多渠道打包&#xff0c;编译不同的资源进行编译处理 一、多渠道打包方式 productFlavor 背景 Android默认提供了Gradle插件库 class…

协同套件——“ 船 ”新版本

空地协同套件自前段时间推出后&#xff0c;受到了很多开发者的关注&#xff0c;不少开发者均表示对跨域机器人协同工作非常感兴趣&#xff0c;这也加快了我们协同套件的另一块拼图-船机协同的研发进度。近期&#xff0c;我们海空协同套件也顺利完成开发测试&#xff0c;本期将给…

基于炬芯3019 SDK数字助听器平台驱动设计与算法实现

+v hezkz17进数字音频系统答疑裙 1 针对数字助听器进行音频信号处理,达到助听功能的需求分析,使用三种语音处理算法。 三种语音处理算法包括:自动增益控制算法、移频算法以及宽动态范围压缩算法。 通过分析三种算法的基本原理,将算法分别使用MATLAB 进行仿真实现,验证算法…