linux系统下C标准库IO缓存区和内核缓存区的区别?
一、linux系统下C标准库IO缓存区和内核缓存区的区别
在Linux系统下,C标准库提供了许多用于IO的函数,如fread、fwrite、fscanf、fprintf等。这些函数使用缓冲区来提高IO性能,其中缓冲区可以分为两种类型:C标准库IO缓存区和内核缓存区。C标准库IO缓存区是在用户空间中的一段内存,用于暂存IO操作的数据,当缓冲区满或者执行fflush等函数时,才会将数据写入到内核缓存区中。此外,C标准库IO缓存区也包括了读取文件时的缓存区,可以减少读取文件时的IO次数,提高读取性能。
C标准库IO缓存区和内核缓存区都可以提高IO性能,但是它们的作用范围不同。C标准库IO缓存区一般用于减少用户空间与内核空间之间的数据传输次数,而内核缓存区则用于减少IO操作对磁盘设备的访问次数,从而提高IO性能。
内核缓存区是内核中的一段内存,用于与硬件设备进行交互的数据缓存区。当程序调用标准库函数向文件写入数据时,数据会首先被复制到C标准库IO缓存区(如果启用了缓冲区),再被C标准库函数调用write()系统调用将数据从用户空间复制到内核缓存区。内核缓存区的大小通常比C标准库IO缓存区大,能够容纳更多的数据,因此它可以减少对磁盘设备的IO操作,提高IO性能。
二、C标准库的I/O缓冲区
UNIX的传统是Everything is a file,键盘、显示器、串口、磁盘等设备在/dev 目录下都有一个特殊的设备文件与之对应,这些设备文件也可以像普通文件(保存在磁盘上的文件)一样打开、读、写和关闭,使用的函数接口是相同的。用户程序调用C标准I/O库函数读写普通文件或设备,而这些库函数要通过系统调用把读写请求传给内核,最终由内核驱动磁盘或设备完成I/O操作。C标准库为每个打开的文件分配一个I/O缓冲区以加速读写操作,通过文件的FILE 结构体可以找到这个缓冲区,用户调用读写函数大多数时候都在I/O缓冲区中读写,只有少数时候需要把读写请求传给内核。
以fgetc / fputc 为例,当用户程序名列前茅次调用fgetc读一个字节时,fgetc 函数可能通过系统调用进入内核读1K字节到I/O缓冲区中,然后返回I/O缓冲区中的名列前茅个字节给用户,把读写位置指 向I/O缓冲区中的第二个字符,以后用户再调fgetc,就直接从I/O缓冲区中读取,而不需要进内核了,当用户把这1K字节都读完之后,再次调用fgetc 时,fgetc 函数会再次进入内核读1K字节到I/O缓冲区中。在这个场景中用户程序、C标准库和内核之间的关系就像在“Memory Hierarchy”中 CPU、Cache和内存之间的关系一样,C标准库之所以会从内核预读一些数据放在I/O缓冲区中,是希望用户程序随后要用到这些数据,C标准库的I/O缓冲区也在用户空间,直接从用户空间读取数据比进内核读数据要快得多。
另一方面,用户程序调用fputc通常只是写到I/O缓冲区中,这样fputc 函数可以很快地返回,如果I/O缓冲区写满了,fputc 就通过系统调用把I/O缓冲区中的数据传给内核,内核最终把数据写回磁盘或设备。有时候用户程序希望把I/O缓冲区中的数据立刻传给内核,让内核写回设备或磁盘,这称为Flush操作,对应的库函数是fflush,fclose函数在关闭文件之前也会做Flush操作。
我们知道main 函数被启动代码这样调用:exit(main(argc, argv))。main 函数return时启动代码会调用exit,exit 函数首先关闭所有尚未关闭的FILE *指针(关闭之前要做Flush操作),然后通过_exit 系统调用进入内核退出当前进程。C标准库的I/O缓冲区有三种类型:全缓冲、行缓冲和无缓冲。当用户程序调用库函数做写操作时, 不同类型的缓冲区具有不同特性。
全缓冲:如果缓冲区写满了就写回内核。常规文件通常是全缓冲的。行缓冲:如果用户程序写的数据中有换行符就把这一行写回内核,或者如果缓冲区写满了就写回内 核。标准输入和标准输出对应终端设备时通常是行缓冲的。无缓冲:用户程序每次调库函数做写操作都要通过系统调用写回内核。标准错误输出通常是无缓冲的,这样用户程序产生的错误信息可以尽快输出到设备。除了写满缓冲区、写入换行符之外,行缓冲还有两种情况会自动做Flush操作。如果用户程序调用库函数从无缓冲的文件中读取,或者从行缓冲的文件中读取,并且这次读操作会引发系统调用从内核读取数据,如果用户程序不想完全依赖于自动的Flush操作,可以调fflush函数手动做Flush操作。
#include int fflush(FILE *stream);//返回值:成功返回0,出错返回EOF并设置error
fflush函数用于确保数据写回了内核,以免进程异常终止时丢失数据,如fflush(stdout);作为一个特例,调用fflush(NULL)可以对所有打开文件的I/O缓冲区做Flush操作。
三、内核缓存区
当一个用户进程要从磁盘读取数据时,内核一般不直接读磁盘,而是将内核缓冲区中的数据复制到进程缓冲区中。但若是内核缓冲区中没有数据,内核会把对数据块的请求,加入到请求队列,然后把进程挂起,为其它进程提供服务。
等到数据已经读取到内核缓冲区时,把内核缓冲区中的数据读取到用户进程中,才会通知进程,当然不同的io模型,在调度和使用内核缓冲区的方式上有所不同。你可以认为,read是把数据从内核缓冲区复制到进程缓冲区。write是把进程缓冲区复制到内核缓冲区。当然,write并不一定导致内核的写动作,比如os可能会把内核缓冲区的数据积累到一定量后,再一次写入。这也就是为什么断电有时会导致数据丢失。所以说内核缓冲区,是为了在OS级别,提高磁盘IO效率,优化磁盘写操作。
延伸阅读1:Linux系统的特点
完全免费完全兼容POSIX 1.0标准多用户、多任务良好的界面丰富的网络功能可靠的安全、稳定性能支持多种平台相关推荐HOT
更多>>mysql的MEMORY引擎为什么没有redis的应用广泛?
一、mysql的MEMORY引擎为什么没有redis的应用广泛从kv缓存的作用看,mysql优点不在kv缓存上,用它做kv缓存维护成本高,redis安装启动使用简单,...详情>>
2023-10-20 18:38:17什么是PWA?
一、什么是PWAPWA是渐进式 Web 应用,运用现代的 Web API 以及传统的渐进式增强策略来创建跨平台 Web 应用程序。。这些应用无处不在、功能丰富...详情>>
2023-10-20 14:02:19软件包“被标记为手动安装”是什么意思?
一、软件包“被标记为手动安装”是什么意思当你尝试安装已安装的库或开发包时,你会看到此消息。意味着该软件包是由用户手动安装的,而不是通过...详情>>
2023-10-20 11:47:20什么是Flash?
一、什么是FlashFlash是一种基于向量图形的动画技术,由Adobe公司开发。它支持多媒体、游戏、网站设计等应用,可以在各种平台和设备上实现高质...详情>>
2023-10-20 10:24:01热门推荐
一个优异的web前端,需要具备哪些条件?
沸华为自研的数据库gaussdb有哪些优势?
热数据库ER图是怎么做的?
热为什么使用MySQL?
新什么是synchronized?
既然MySQL中InnoDB使用MVCC,为什么REPEATABLE-READ不能消除幻读?
分布式系统里用户ID生成有什么好的方法和规则能满足“少数、尽量短、不能直接看出规则”这几个条件?
isKindOfClass、isMemberOfClass 作用分别是什么?
APP开发流程步骤有哪些?
mysql的MEMORY引擎为什么没有redis的应用广泛?
webpack proxy工作原理为什么能解决跨域?
python的五个特点?
staticmethod和classmethod的区别?
Android App设计开发应遵循哪些原则?