Linux系统的I/O操作涉及的内核缓冲区
一. Linux系统中I/O操作
Linux系统中,常见的I/O操作,如 read() 函数或 write() 函数。
在调用 write() 函数时,我们认为该函数一旦返回,数据便已经写到了文件中,但是这种概念只是宏观上的。实际上,操作系统实现某些文件 I/O 时(如磁盘文件),为了保证I/O的效率,在内核通常会用到一片专门的区域(内存或独立的I/O地址空间)作为 I/O 数据缓冲区。它用在输入输出设备和CPU之间,用来缓存数据,使得低速的设备和高速的 CPU 能够协调工作,避免低速的输入输出设备长时间占用CPU,减少系统调用,提高了 CPU 的工作效率。
二. Linux 系统中的内核缓冲区
1. 延迟写:
UNIX 或 Linux 系统在设计时使用了内核缓冲区。
Linux系统的延迟写原理:大多数磁盘 I/O 都通过缓存进行,当将数据写到文件上时,通常该数据先由内核复制到缓存中,如果该缓存尚未写满,则并不将其排入输出队列,而是等待其写满或者当内核需要刷新缓冲时,再将该缓存写入输出队列,然后等待其到达队首时,才进行实际的 I/O 操作。这种输出方式被称为延迟写。
2. Linux系统中同步接口函数
为了保证磁盘上实际文件系统与缓存中内容的一致性,系统提供了同步接口,包括 sync() 函数、fsync() 函数与 fdatasync() 函数。同步缓存函数如下:
sync() 函数:
#include <unistd.h>
void sync(void);
函数sync() 始终成功。但是 sync() 只是将所有修改过的块的缓存排入写队列,然后就返回,它并不等待实际I/O 操作结束。系统守候进程一般每隔一段时间调用一次 sync() 函数。这就保证了定期刷新内核的块缓存。
fsync() 函数 与 fdatasync() 函数:
int fsync(int fd);
int fdatasync(int fd);
fsync() 函数则等待 I/O 结束,然后返回。fsync() 多用于数据库相关的应用程序,它确保修改过的块立即写到磁盘中。
fdatasync() 只是更新内容,如果没有必要,并不更新元数据(即该文件的属性,例如上次修改内容的时间)。
如果执行成功时,fsync()函数/fdatasync()函数返回0;否则返回-1,同时设置 errno 以指明错误。
三. 总结
磁盘I/O操作中提供的这种延迟写机制,虽然减少了磁盘读写次数,可以有效的提供 CPU 工作效率。但是缺点是:降低了文件内容的更新速度,使得欲写到文件中的数据在一段时间内并没有写到磁盘上。当系统发生故障时,这种延迟可能造成文件更新内容的丢失。
所以,这种延迟读写机制,有利有弊。