同步内核缓冲区

1.缓冲区简介

人生三大错觉之一:在调用函数write()时,我们认为该函数一旦返回,数据便已经写到了文件中.但是这种概念只是宏观上的.实际上,操作系统实现某些文件I/O时(如磁盘文件),为了保证I/O的效率,在内核通常会用到一片专门的区域(内存或独立的I/O地址空间)作为I/O数据缓冲区.它用在输入输出设备和CPU之间,用来缓存数据,使得低速的设备和高速的CPU能够协调工作避免低速的输入输出设备长时间占用CPU,减少系统调用,提高了CPU的工作效率.

2.不同步的write()

传统的UNIX或LINUX系统在设计时使用了内核缓冲区,设有高速缓冲区或页面高速缓冲区,大多数磁盘I/O都通过缓冲区进行.当将数据写入文件时,内核通常先将该数据复制到其中一个缓冲区,如果该缓冲区尚未写满,则并不将其排入输出队列,而是等待其写满或者当内核需要重用该缓冲区以便存放其他磁盘块数据时,再将该缓冲区排入输出队列;然后待其到达队首时,才进行实际的I/O操作.这种输出方式被称为延迟写.
当调用write()函数写出数据时,数据一旦写到该缓冲区(关键:只是写到缓冲区),函数便立即返回.此时写出的数据可以用read()读回,也可以被其他进程读到,但是并不意味着它们已经被写到了外部永久存储介质上,即使调用close()关闭文件后也可能如此. 因为缓冲区的数据可能还在等待输出.
因此,从数据被实际写到磁盘的角度来看,用write()写出的文件数据与外部存储设备并不是完全同步的.不同步的时间间隔非常短,一般只有几秒或十几秒,具体取决于写出的数据量和I/O数据缓冲区的状态.尽管不同步的时间间隔很短,但是如果在此期间发生掉电或者系统崩溃,则会导致所写数据来不及写至磁盘而丢失的情况.
注意:内核将缓冲区中的数据“写”到标准输入磁盘文件中,这里“写”不是将缓冲区中的数据移动到磁盘文件中,而是拷贝到磁盘文件中,也就说此时磁盘文件中还保留一份缓冲区内容的备份.如图1所示.做出这一设计也是有其道理的,如果写出到磁盘文件上,磁盘坏了或满了等等,总之就是无法将数据送出,假如没备份,那数据不是丢掉了.也就是说内核会等待写入磁盘动作完成后,才放心的将备份的数据删除掉.在下文讨论的三个函数中也将涉及到这个过程.

图1 数据传入过程示意图

为了保证磁盘上实际文件系统与缓冲区高速缓存中内容的一致性,UNIX系统提供了sync、fsync和fdatasync三个函数.

3.sync函数

头文件:#include<unistd.h>
定义函数:void sync(void);
返回值:若成功则返回0,若出错则返回-1,同时设置errno以指明错误.
函数说明:
sync负责将系统缓冲区的数据“写入”磁盘,以确保数据的一致性和同步性.注意:sync函数只是将所有修改过的块缓冲区排入写队列,然后就返回,他并不等待实际I/O操作结束.所以不要认为调用了sync函数,就觉得数据已安全的送到磁盘文件上,有可能会出现问题,但是sync函数是无法得知的.
系统守候进程一般每隔一段时间调用一次sync函数,确保定期刷新内核的块缓存.UNIX系统中,系统守候进程update会周期性地(一般每个30秒)调用sync函数.命令sync(1)也调用sync函数.

4.fsync函数

头文件:#include<unistd.h>
定义函数:int fsync(int filedes);
返回值:若成功则返回0,若出错则返回-1,同时设置errno以指明错误.
函数说明:
与sync函数不同,fsync函数只对由文件描符filedes指定的单一文件起作用,强制与描述字fildes相连文件的所有修改过的数据(包括核内I/O缓冲区中的数据)传送到外部永久介质,即刷新fildes给出的文件的所有信息,并且等待写磁盘操作结束,然后返回.调用 fsync()的进程将阻塞直到设备报告传送已经完成.这个fsync就安全点了.
一个程序在写出数据之后,如果继续进行后续处理之前要求确保所写数据已写到磁盘,则应当调用fsync().例如, 数据库 应用通常会在调用write()保存关键交易数据的同时也调用fsync().这样更能保证数据的安全可靠.

5.fdatasync函数

头文件:#include<unistd.h>
定义函数:int fdatasync(int filedes);
返回值:若成功则返回0,若出错则返回-1,同时设置errno以指明错误.
函数说明:
fdatasync函数类似于fsync函数,但它只影响文件数据部分,强制传送用户已写出的数据至物理存储设备,不包括文件本身的特征数据.这样可以适当减少文件刷新时的数据传送量.而除数据外,fdatasync还会同步更新文件的属性.

6.错误代码

EBADF:文件描述符无效,或文件已关闭.
EIO : 读写的过程中发生错误 .
EROFS, EINVAL:文件所在的文件 系统 不支持同步.

7.fflush()与fsync()的联系

内核I/O缓冲区是由操作系统管理的空间,而流缓冲区是由标准I/O库管理的用户空间.fflush()只刷新位于用户空间中的流缓冲区.fflush()返回后,只保证数据已不在流缓冲区中,并不保证它们一定被写到了磁盘.此时,从流缓冲区刷新的数据可能已被写至磁盘,也可能还待在内核I/O缓冲区中.要确保流I/O写出的数据已写至磁盘,那么在调用fflush()后还应当调用fsync().

8.综述

虽然延迟写减少了磁盘读写次数,但是却降低了文件内容的更新速度,使得欲写到文件中数据在一段时间内并没有写到磁盘上。当系统发生故障时,这种延迟可能造成文件更新内容的丢失。

同步I/O sync、fsync和fdatasync函数相关推荐

  1. linux同步IO: sync、fsync与fdatasync

    转载地址:https://blog.csdn.net/cywosp/article/details/8767327 传统的UNIX实现在内核中设有缓冲区高速缓存或页面高速缓存,大多数磁盘I/O都通过缓 ...

  2. linux 同步IO: sync msync、fsync、fdatasync与 fflush

    最近阅读leveldb源码,作为一个保证可靠性的kv数据库其数据与磁盘的交互可谓是极其关键,其中涉及到了不少内存和磁盘同步的操作和策略.为了加深理解,从网上整理了linux池畔同步IO相关的函数,这里 ...

  3. sync、fsync、fdatasync、fflush函数区别和使用举例

    sync.fsync.fdatasync.fflush函数区别和使用举例 Linux/unix在内核中设有缓冲区.高速缓冲或页面高速缓冲,大多数磁盘I/O(block device)都通过缓冲进行,当 ...

  4. Linux sync/fsync/fdatasync 函数

    文章目录 一.函数声明 二.意义 三.实例 四.fsync和fdatasync所说的更新文件属性,指的是更新哪些文件的属性呢. 一.函数声明 #include <unistd.h>int ...

  5. linux 同步IO: sync、fsync与fdatasync、sys_sync【转】

    本文转自:http://blog.csdn.net/cywosp/article/details/8767327 和 http://www.2cto.com/os/201204/126687.html ...

  6. Linux sync 、fsync 和 fdatasync详解

      ES 里,摒弃了 fsync,嫌它太耗时, 它使用了数据的冗余备份来实现的数据的安全性. 传统的UNIX实现在内核中设有缓冲区高速缓存或页面高速缓存,大多数磁盘I/O都通过缓冲进行.当将数据写入文 ...

  7. Linux fsync和fdatasync系统调用实现分析(Ext4文件系统)

    在Linux系统中,对文件系统上文件的读写一般是通过页缓存(page cache)进行的(DirectIO除外),这样设计的可以延时磁盘IO的操作,从而可以减少磁盘读写的次数,提升IO性能.但是性能和 ...

  8. Go 学习笔记(66)— Go 并发同步原语(sync.Mutex、sync.RWMutex、sync.Once)

    1. 竞态条件 一旦数据被多个线程共享,那么就很可能会产生争用和冲突的情况.这种情况也被称为竞态条件(race condition),这往往会破坏共享数据的一致性. 举个例子,同时有多个线程连续向同一 ...

  9. mysql timespec重定义_MySQL:半同步(二)主库端回调函数

    源码版本5.7.29 主库端的回调函数比较多,比较复杂 一.回调函数:repl_semi_binlog_dump_start 调用线程:dump线程 #0 repl_semi_binlog_dump_ ...

  10. PowerPC指令集结构之同步指令:Sync和Isync

    PowerPC指令集结构之同步指令:Sync和Isync Note:翻译自SynchronizingInstructions for PowerPC Instruction Set Architect ...

最新文章

  1. python 模拟浏览器selenium 微信_Spider-Python爬虫之使用Selenium模拟浏览器行为
  2. jdbc在项目中的应用
  3. 一分钟了解阿里云产品:容器服务概述
  4. postman 变量
  5. 华为2018软件岗笔试题解题思路和源代码分享
  6. MYSQL导入数据出现ERROR 1049 (42000): Unknown database 'n??;'
  7. 机器学习基础算法19-决策树实践-决策树回归-决策树用于拟合
  8. Pandas 的轴向连接 concat
  9. FORM开发实现动态LOV
  10. 线段树相关(研究总结,线段树)
  11. java实战项目教程
  12. ISIS开发出加密安卓通信软件
  13. php网站登录界面验证码打不开,php网站无法显示验证码
  14. windows通过资源管理器访问服务器(samba服务),您需要权限来执行此操作
  15. 为什么你还没有买新能源汽车?
  16. Python装逼神器,5 行 Python 代码 实现一键批量扣图!
  17. 数据挖掘算法揭秘篇——分类方法(一)
  18. 微信小程序实现星星评分
  19. J2EE下使用AJAX(四) 隐藏帧 -- 史前的AJAX实现
  20. 力扣有没有java_力扣 APP 全新改版,史诗级增强!

热门文章

  1. 分金币 (UVA 11300)
  2. 查看最大的10个文件
  3. C语言实现数字串转数字
  4. 微型计算机配置单怎么写,微型计算机的组成和配置.doc
  5. generator.xml mysql_generatorConfig-mysql.xml中连接数据库的正确书写方式。
  6. goback history 传递参数_vue-router go(-1)后退时怎么带参数?
  7. agax分页查询必知知识,分页必须参数详解
  8. java统计空格代码_java统计文件中字符,数字,汉字,空格数目
  9. php v9搜索不到内容,關於如何解決PHPCMS V9內容搜索顯示不全問題解決方案
  10. 当出现“在当前位置发现已经存在为RESUME.XLW的文件。您希望将该文件替换掉吗?” 解决方案...