当前位置: 首页 > news >正文

模拟进程通过系统调用向缓冲区写入并刷新的过程

目录

fsync

模拟进程通过系统调用向缓冲区写入并刷新的过程

my_stdio.h设计

mfopen设计

mfwrite设计

mfflush设计

mflose设计


今天我们通过几十行代码来自己做一个简单的缓冲区。

昨天有个问题没有讲清楚,如下:

父进程创建了文件并写入,那为什么子进程也可以访问到这个文件并刷新缓冲区,问题的后面昨天解答了,为什么子进程也可以访问到文件呢?

相当于子进程完完全全继承了父进程在文件描述符表的信息,这和页表的拷贝有点像的。

fsync

由于close在系统层面不会之间刷新缓冲区,我们如果要调用系统的函数来强制刷新缓冲区就需要使用fsync函数

看不懂是干什么的很正常,参数就一个,就是传一个文件描述符,fsync 负责强制把内存中的数据同步到磁盘,确保数据持久化。相当于手动的刷新对应fd文件的文件缓冲区。

但是会强制同步到磁盘,会强制执行这个操作,直接将文件挂起,fsync 会强制将数据从内存缓冲区(Page Cache)同步到磁盘,而不是让操作系统自行调度刷新,如果磁盘 I/O 负载已经很高,再次调用 fsync 会让磁盘更忙,影响其他 I/O 操作,比如数据库查询、日志写入等。

fsync 是一个阻塞操作,在数据真正落盘前,调用它的进程会被挂起,如果多个线程或进程频繁调用 fsync,可能会导致严重的性能下降,甚至造成系统卡顿。在极端情况下,如果所有进程都在等待 fsync 完成,而磁盘负载过高,可能会导致 I/O 死锁或超时问题。

怎么解决呢,它的下面还有函数可以极大的提高效率,fdatasync(fd)只同步数据,不同步元数据,所以比 fsync 更高效。

成功刷新!!!

模拟进程通过系统调用向缓冲区写入并刷新的过程

由于用户级缓冲区存在FILE结构体内部,所以我们这次主要的就是模仿文件创建,读写和刷新缓冲区的操作。这个代码总体还是特别简单的,只要你之前C语言通讯录那个代码会自己打个大概,相信这个不会太难的。

my_stdio.h设计

在mFILE结构体当中写入缓冲区buffer,这个一般是malloc出来的,但是我们这次就简单一点直接创建1024个空间就可以了,然后结构体包含元素有缓冲区刷新方式flag,三种方式如上,文件描述符,再加两个缓冲区的总容量capable和当前占用了多少size。

mFILE* mfopen(const char* filename, const char* mode);是文件创建函数,像C语言的fopen一样,传入一个待文件的地址和文件要打开并执行的模式。

int mfwrite(const char* ptr, int num, mFILE* stream);是写函数,这个二进制写在glibc里面是有四个参数的,我们简单点就3个,ptr是代写入的内容,num是写入的个数,stream是写入的文件地址。

void mfflush(mFILE* stream);是刷新缓冲区的函数,唯一参数是写入的文件地址。

 void mfclose(mFILE* stream);是关闭文件函数,唯一参数是写入的文件地址。

在.h里面完全就是准备阶段。这里有人要问了,为什么不直接包含头文件呢,我们以前都是这么干的呀,这里是因为,我们这个程序将来有可能要跨平台或跨文件去用的,只需要将.c文件弄成.o再链接别人的main.o(测试文件)就可以在被人的电脑上跑了,如果.c里面没有头文件的话就找不到了,那个.h在别人的电脑上是看不到的。

mfopen设计

C语言的创建文件函数本质在底层就是封装了系统调用的open,所以我们也只直接调用系统的open来创建,我们先判断传入的mode(文件执行方式),依照不同的执行方式进行创建不同使用权限的文件,然后返回一个fd,如果创建失败或者用户输入的mode不在比较范围那原有初始化的fd肯定不变(<0),就返回空了,在创建成功后,需要malloc一个FILE,初始化FILE里面的对象,我们再次默认刷新方式使用行刷新,最后返回值别忘了。

这部分的头文件比较多,逻辑参考如上。

mfwrite设计

创建成功文件后或者文件已经存在了,就开始写入工作,由于系统文件刷新缓冲区是调用的写函数write,但是这个过程是先写入然后刷新后再写入系统的内核缓冲区的也就是文件里面。我们这里也不直接写入,我们先默认模式是追加,所以只需要拷贝到buffer的特定位置就可以了,反正每次拷贝都会覆盖之前的而又带入新的。然后判断释放要刷新缓冲区,判断规则为buffer最后一个字符是/n,并且选择的是行刷新,最后别忘了要有数据才刷新size > 0,如果以上三个条件都满足了,那就调用mfflush函数刷新缓冲区,写入文件,否则这么写入buffer就可以了。

mfflush设计

原系统调用的是write系统调用来刷新用户级的缓冲区然后写入内存的,刷新缓冲区函数直接调用write就可以达到刷新的目的,当然你也可以再接着使用fsync来强制刷新系统级的内核的缓冲区。然后最后别忘了size重置成0。

mflose设计

这个函数呀有一个细节,由于fcloseC语言函数内部又是直接封装调用的系统调用close,所以我们等下关闭文件的时候也是调用的这个,但是在此之前需要检查一下对应的缓冲区还有没有数据,有的话需要先刷新掉。

我们等下再进行测试,设计的总体思路就是这样的。

相关文章:

  • k8s之pod的调度之污点与容忍污点,什么是污点? 如何容忍污点
  • 校园二手交易微信小程序的设计与实现(论文源码调试讲解)
  • 在鸿蒙HarmonyOS手机上安装hap应用
  • 深度学习基础--ResNet50V2网络的讲解,ResNet50V2的复现(pytorch)以及用复现的ResNet50做鸟类图像分类
  • 【北京迅为】iTOP-RK3568OpenHarmony系统南向驱动开发-第1章 GPIO基础知识
  • 线程概述以及Java中线程的三种创建方式(继承Thread类、实现Runnable接口、实现Callable接口)
  • 鸿蒙 ArkUI 实现 2048 小游戏
  • 网络安全 越权分为几种
  • Centos7源码编译安装Sqlite最新版本
  • 算法-二叉树篇14-从中序与后序遍历序列构造二叉树
  • 深度解析 ANSI X9.31 TR-31:金融行业密钥管理核心标准20250228
  • 如何有效判断与排查Java GC问题
  • Spring 源码硬核解析系列专题(十):Spring Data JPA 的 ORM 源码解析
  • 【Spring】AOP
  • PMP项目管理—范围管理篇—6.控制范围
  • 轻松微调大模型:利用 Colab 和 Unsloth 实现高效训练
  • 企业微信里可以使用的企业内刊制作工具,FLBOOK
  • 1.2.3 使用Spring Initializr方式构建Spring Boot项目
  • Python在实际工作中的运用-指定目录内所有Excel文件转CSV
  • Qt基于信号量QSemaphore实现的生产者消费者模型
  • 手机高端网站开发/针对大学生推广引流
  • 婚纱摄影网站html/西安网站关键词优化费用
  • 做视频网站玩什么配置/互联网营销案例分析
  • 清河哪里做网站/宁德市是哪个省
  • 传媒公司网站建设方案/搜索引擎营销的主要方法包括
  • 备案怎么关闭网站吗/cnzz