【Linux系统化学习】缓冲区

2024-02-17 23:28

本文主要是介绍【Linux系统化学习】缓冲区,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

目录

缓冲区

 一个样例

现象解释

缓冲区存在的位置


缓冲区

在刚开始学习C语言的时候我们就听过缓冲区这个名词,很是晦涩难懂;在Linux下进程退出时也包含缓冲区,因此缓冲区到底是什么?有什么作用?

让我们先从一个小故事说起:

身在西藏上大学的张三有一个在海南的朋友李四,李四马上过生日了张三想要送李四一个键盘;于是张三定了各种交通工具的票,自己带着键盘千里迢迢的跑到海南张三的楼下送给张三,又千里迢迢的原路返回,这一来回耽误了张三好多的时间和精力。

又是一年,李四又过生日了;张三想送李四一个鼠标。打听到自己家和张三家楼下都有菜鸟驿站于是将鼠标交给菜鸟驿站,通过菜鸟驿站的快递小哥千里迢迢的将鼠标送到李四家楼下的菜鸟驿站。张三自己不用跑这一个来回。但是菜鸟驿站不可能因为张三一个鼠标进行派送,先暂存一部分快递要等到快递车装满进行派送,或者一行存储柜子满了在派送。但是也有可能特殊情况顾客“加钱”,想要直接派送。

上面这个故事中的菜鸟驿站就是我们口中的缓冲区

缓冲区的作用提高使用者的效率

因此缓冲区是内存空间的一部分。也就是说,在内存空间中预留了一定的存储空间,这些存储空间用来缓冲输入或输出的数据,这部分预留的空间就叫做缓冲区。

暂存快递等到快递车装满派送:全缓冲(缓冲区满了刷新)

“加钱”直接派送:无缓冲(立即刷新)

暂存一行存储柜派送:行缓冲(一行满了刷新)

这是一般的刷新策略,特殊情况

  • 强制刷新
  • 进程推出的时候,一般要进行刷新缓冲区

一般对于显示器文件:行刷新(行缓冲),对于磁盘上的文件:全缓冲

 一个样例

 1 #include<stdio.h>2 #include<string.h>3 #include<unistd.h>                                                                                                                                       4 int main()5 {6     fprintf(stdout,"hello fprintf\n");7     printf("hello print\n");8     fputs("hello fputs\n",stdout);9 10     //系统调用11     const char * str = "system call : hello write\n";12     write(1,str,strlen(str));13     return 0;14 }

  1 #include<stdio.h>2 #include<string.h>3 #include<unistd.h>4 int main()5 {6     fprintf(stdout,"hello fprintf\n");7     printf("hello print\n");8     fputs("hello fputs\n",stdout);9 10     //系统调用11     const char * str = "system call : hello write\n";12     write(1,str,strlen(str));13     fork();                                                                                                                                              14     return 0;15 }

上面第一种情况在最后没有创建子进程直接执行和重定向到某个文件中也没有什么问题,就是在重定向时系统调用接口先执行;

第二种情况是在程序运行最后使用fork函数创建子进程直接执行程序时没有问题,但是在重定向时除了系统调用,剩下的语句被执行了两次。

现象解释

  • 当我们直接向显示器进行打印的时候,显示器文件的刷新方式是行刷新。而代码输出的所有字符串,都有”\n",fork之前数据已经全部刷新包括system call。
  • 重定向到log.txt,本质是向磁盘文件中写入,我们系统对于数据的刷新方式已经由行刷新变成了全缓冲。
  • 全缓冲意味着缓冲区变大,实际写入的简单数据不足以把缓冲区写满,fork执行的时候数据依旧在缓冲区中。
  • 当前阶段的缓冲区是用户缓冲区是C语言和操作系统没有任何关系。
  • C/C++提供的缓冲区,里面保存的是用户的数据,是属于当前进程;如果把这个数据交给操作系统,这个数据就数据操作系统。
  • 当进程推出的时候,一般要进行刷新缓冲区,即使这个数据没有满足刷新条件;刷新缓冲区属于对文件的写入操作;fork立马退出,任意一个进程在推出的时候都会刷新缓冲区,就要发生写时拷贝。
  • 系统调用没有使用C语言的缓冲区,直接写入到操作系统,不属于进城了不发生写时拷贝。
  • 从C语言的缓冲区写入到操作系统中这个过程就是刷新

缓冲区存在的位置

 

我们在使用C语言的一些文件操作接口时会发现很多函数的的返回值或者函数参数的类型为FILE*,之前的文章中我们提到过Linux下的文件描述符也是在FILE中的;不难猜测出C语言中的缓冲区存在在FILE中。当我们查看C语言的源码可以证实这一点:

我们来看看FILE的部分结构

typedef struct _IO_FILE FILE; 在/usr/include/stdio.h

在/usr/include/libio.h
struct _IO_FILE {
int _flags; /* High-order word is _IO_MAGIC; rest is flags. */
#define _IO_file_flags _flags
//缓冲区相关
/* The following pointers correspond to the C++ streambuf protocol. */
/* Note: Tk uses the _IO_read_ptr and _IO_read_end fields directly. */
char* _IO_read_ptr; /* Current read pointer */
char* _IO_read_end; /* End of get area. */
char* _IO_read_base; /* Start of putback+get area. */
char* _IO_write_base; /* Start of put area. */
char* _IO_write_ptr; /* Current put pointer. */
char* _IO_write_end; /* End of put area. */
char* _IO_buf_base; /* Start of reserve area. */
char* _IO_buf_end; /* End of reserve area. */
/* The following fields are used to support backing up and undo. */
char *_IO_save_base; /* Pointer to start of non-current get area. */
char *_IO_backup_base; /* Pointer to first valid character of backup area */
char *_IO_save_end; /* Pointer to end of non-current get area. */
struct _IO_marker *_markers;
struct _IO_FILE *_chain;
int _fileno; //封装的文件描述符
#if 0
int _blksize;
#else
int _flags2;
#endif
_IO_off_t _old_offset; /* This used to be _offset but it's too small. */
#define __HAVE_COLUMN /* temporary */
/* 1+column number of pbase(); 0 is unknown. */
unsigned short _cur_column;
signed char _vtable_offset;
char _shortbuf[1];
/* char* _save_gptr; char* _save_egptr; */
_IO_lock_t *_lock;
#ifdef _IO_USE_OLD_IO_FILE
};

今天对Linux下缓冲区的分享到这就结束了,希望大家读完后有很大的收获,也可以在评论区点评文章中的内容和分享自己的看法;个人主页还有很多精彩的内容。您三连的支持就是我前进的动力,感谢大家的支持!!! 

 

这篇关于【Linux系统化学习】缓冲区的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/719314

相关文章

Linux join命令的使用及说明

《Linuxjoin命令的使用及说明》`join`命令用于在Linux中按字段将两个文件进行连接,类似于SQL的JOIN,它需要两个文件按用于匹配的字段排序,并且第一个文件的换行符必须是LF,`jo... 目录一. 基本语法二. 数据准备三. 指定文件的连接key四.-a输出指定文件的所有行五.-o指定输出

Linux jq命令的使用解读

《Linuxjq命令的使用解读》jq是一个强大的命令行工具,用于处理JSON数据,它可以用来查看、过滤、修改、格式化JSON数据,通过使用各种选项和过滤器,可以实现复杂的JSON处理任务... 目录一. 简介二. 选项2.1.2.2-c2.3-r2.4-R三. 字段提取3.1 普通字段3.2 数组字段四.

Linux kill正在执行的后台任务 kill进程组使用详解

《Linuxkill正在执行的后台任务kill进程组使用详解》文章介绍了两个脚本的功能和区别,以及执行这些脚本时遇到的进程管理问题,通过查看进程树、使用`kill`命令和`lsof`命令,分析了子... 目录零. 用到的命令一. 待执行的脚本二. 执行含子进程的脚本,并kill2.1 进程查看2.2 遇到的

Linux云服务器手动配置DNS的方法步骤

《Linux云服务器手动配置DNS的方法步骤》在Linux云服务器上手动配置DNS(域名系统)是确保服务器能够正常解析域名的重要步骤,以下是详细的配置方法,包括系统文件的修改和常见问题的解决方案,需要... 目录1. 为什么需要手动配置 DNS?2. 手动配置 DNS 的方法方法 1:修改 /etc/res

Linux创建服务使用systemctl管理详解

《Linux创建服务使用systemctl管理详解》文章指导在Linux中创建systemd服务,设置文件权限为所有者读写、其他只读,重新加载配置,启动服务并检查状态,确保服务正常运行,关键步骤包括权... 目录创建服务 /usr/lib/systemd/system/设置服务文件权限:所有者读写js,其他

Linux下利用select实现串口数据读取过程

《Linux下利用select实现串口数据读取过程》文章介绍Linux中使用select、poll或epoll实现串口数据读取,通过I/O多路复用机制在数据到达时触发读取,避免持续轮询,示例代码展示设... 目录示例代码(使用select实现)代码解释总结在 linux 系统里,我们可以借助 select、

Linux挂载linux/Windows共享目录实现方式

《Linux挂载linux/Windows共享目录实现方式》:本文主要介绍Linux挂载linux/Windows共享目录实现方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地... 目录文件共享协议linux环境作为服务端(NFS)在服务器端安装 NFS创建要共享的目录修改 NFS 配

linux系统中java的cacerts的优先级详解

《linux系统中java的cacerts的优先级详解》文章讲解了Java信任库(cacerts)的优先级与管理方式,指出JDK自带的cacerts默认优先级更高,系统级cacerts需手动同步或显式... 目录Java 默认使用哪个?如何检查当前使用的信任库?简要了解Java的信任库总结了解 Java 信

Linux命令rm如何删除名字以“-”开头的文件

《Linux命令rm如何删除名字以“-”开头的文件》Linux中,命令的解析机制非常灵活,它会根据命令的开头字符来判断是否需要执行命令选项,对于文件操作命令(如rm、ls等),系统默认会将命令开头的某... 目录先搞懂:为啥“-”开头的文件删不掉?两种超简单的删除方法(小白也能学会)方法1:用“--”分隔命

Linux五种IO模型的使用解读

《Linux五种IO模型的使用解读》文章系统解析了Linux的五种IO模型(阻塞、非阻塞、IO复用、信号驱动、异步),重点区分同步与异步IO的本质差异,强调同步由用户发起,异步由内核触发,通过对比各模... 目录1.IO模型简介2.五种IO模型2.1 IO模型分析方法2.2 阻塞IO2.3 非阻塞IO2.4