首页 > 编程语言 >系统编程:控制文件I/O的内核缓冲之sync(),fsync()和fdatasync()

系统编程:控制文件I/O的内核缓冲之sync(),fsync()和fdatasync()

时间:2023-11-01 22:00:59浏览次数:38  
标签:文件 fsync sync IO 缓冲区 磁盘 fdatasync 数据

     

   通过系统编程:从write()和fwrite()谈开来我们知道了系统调用和glibc库函数为了提升性能而设立的缓冲区,那么,什么情况下数据会从上一次缓冲区刷新到下一层存储介质(可能是缓冲区,也可能是永久存储介质)呢?fflush()库函数提供了强制将stdio库函数缓冲区数据刷新到内核缓冲区的功能,那么从内核缓冲区到磁盘呢?本文介绍的函数fsync()和fdatasync()将关注这个问题。

同步I/O数据完整性和同步I/O文件完整性

  在介绍具体函数之前,先介绍两个概念:是同步IO数据完整性(synchronized IO data integrity completion)和同步IO文件完整性(synchronized IO file integrity completion)。SUSv3给出的同步IO完成定义:某一IO操作,要么你已经成功完成到磁盘的数据传输,要么被诊断为不成功。

  我们知道,内核对于一个文件的存储,主要是两类信息:用户写入数据内容本身和文件元数据,元数据包括文件属主、属组、文件权限、大小、链接数量、时间戳、指向文件数据块的指针等等。那么,synchronized IO data integrity completion旨在确保针对文件的一次更新传递了足够的信息到磁盘,以便读写操作对数据的获取:

  • 就读操作而言,这意味着被请求的文件数据已经从磁盘传递给了进程。若存在任何影响到所请求数据的挂起写操作,那么在执行读操作之前,会将这些数据传递到磁盘。(笔者:读到的数据一定是和磁盘上的数据是一致的。)
  • 就写操作而言,这意味着写请求所指定的数据已传递至磁盘完毕,且用于获取数据的文件元数据也已传递到磁盘完毕。这里要点在于,要获取文件数据,并非需要所有修改过的文件元数据。(笔者:更改的数据传输到磁盘,并且读取更改数据所需要的部分元数据也传输到磁盘,而并非所有变动的元数据。)

  在知道了synchronized IO data integrity completion之后,synchronized IO file integrity completion的含义也呼之欲出了,后者是前者的超集,它意味着,文件的一次更新过程,要将所有变更的元数据都传递到磁盘。

fsync()

  fsync()系统调用将使缓冲数据和与打开文件描述符fd相关的所有元数据都刷新到磁盘上。调用fsync()会强制是文件处于synchronized IO file integrity completion状态。

#include <unistd.h>

// Returns 0 on success, or -1 on error
int fsync(int fd);

仅在对磁盘设备(或者至少是其高速缓存)的传递完成后,函数才返回。

在调用open()系统调用时如果指定了O_SYNC标志,fd = open(pathneme, O_WRONLY | O_SYNC); 则会使后续输出遵循synchronized IO file integrity completion语义。

fdatasync()

  fdatasync()系统调用的功能类似fsync(),但是只会前置文件处于synchronized IO data integrity completion状态。

#include <unistd.h>

// Returns 0 on success, or -1 on error
int fdatasync(int fd);

fdatasync()可能会减少对磁盘操作的次数,由fsync()调用请求从2次变为1次。例如,若修改了文件数据,文件大小不变,那么fdatasync()只会更新数据(不刷新时间戳到磁盘),而fsync()则会强制刷新文件数据和元数据。

sync()

sync()系统调用会使包含更新文件信息的所有内核缓冲区(即数据库、指针块、元数据等)刷新到磁盘上。

#include <unistd.h>

void sync(void);

在Linux实现中,sync()调用仅在所有数据已经传递到磁盘上(或者至少到其高速缓存)时返回。

若内容发生变化的内核缓冲区在30秒内未经显式方式同步到磁盘上,则一条长期运行的内核线程会确保将其刷新到磁盘上。这一做法是为了规避缓冲区与相关磁盘文件内容长期处于不一致状态(以至于在系统崩溃时发生数据丢失)的问题。在Linux2.6版本中,该任务由pdflush内核线程执行。

性能

  下表给出了采用不同缓冲区大小,在有、无O_SYNC标志情况下将1MB字节写入一个EXT2文件系统格式的文件中的时间。

  简单的测试场景就可以看出,频繁调用fsync()、fdatasync()或sync()对性能影响极大,如果不使用磁盘的高速缓存,性能影响就恶劣。

  如果在程序设计中,需要强制刷新内核缓冲区,那么就应该考虑是否使用大尺寸的write()缓冲区,或者在调用fsync()或fdatasync()时谨慎行事,而不是在打开文件时就加上O_SYNC标志。

 参考

  1. Linux系统编程手册,[德] Michael Kerrisk

标签:文件,fsync,sync,IO,缓冲区,磁盘,fdatasync,数据
From: https://www.cnblogs.com/changry/p/17793928.html

相关文章

  • `async` 函数没有使用 `await` 的执行顺序
    async函数没有使用await的执行顺序什么是async函数?async是JavaScript中的一个关键字,用于定义异步函数。异步函数返回一个Promise对象,但如果没有使用await,它将不会等待异步操作的完成。基本概念在async函数内没有使用await时,执行顺序遵循以下基本原则:立即执行async函......
  • Spring Boot - @Transactional 标注的方法如何使用 synchronized?
    这篇文章中有说到@Transactional标注的方法也有锁的情况下会出现一些问题,具体请看SpringBoot锁。而且Idea也会标一个黄色波浪线提示你。我是这样做的,仅供参考。file:[DiscussionService.java]@ServicepublicclassDiscussionServiceimplementsIDiscussionService{......
  • 理解 JavaScript 的 async/await
    1.async和await在干什么任意一个名称都是有意义的,先从字面意思来理解。async是“异步”的简写,而await可以认为是asyncwait的简写。所以应该很好理解async用于申明一个function是异步的,而await用于等待一个异步方法执行完成。另外还有一个很有意思的语法规定,awai......
  • BlockingQueue---SynchronousQueue
    概述A{@linkplainBlockingQueueblockingqueue}inwhicheachinsertoperationmustwaitforacorrespondingremoveoperationbyanotherthread,andviceversa.Asynchronousqueuedoesnothaveanyinternalcapacity,notevenacapacityofone.......
  • 使用async/await与forEach循环结合
    内容来自DOChttps://q.houxu6.top/?s=使用async/await与forEach循环结合在forEach循环中使用async/await是否有问题?我试图遍历一个文件数组,并对每个文件的内容使用await。importfsfrom'fs-promise'asyncfunctionprintFiles(){constfiles=awaitgetFilePaths()......
  • C++多线程——async、packages_task、promise
    异步编程async、future基本概念和使用:异步执行函数:std::async可以异步执行一个函数,这意味着函数将在后台线程中执行,而当前线程可以继续执行其他任务。返回值获取:你可以获得函数的返回值,或者得到一个std::future对象,它允许你在将来的某个时刻获取函数的结果。线程......
  • 20 Synchronized和Lock的实现原理与区别
    相同点:(1)都是可重入锁(2)都保证了可见性和互斥性(3)都可以用于控制多线程对共享对象的访问不同点:(1)ReentrantLock等待可中断(2)synchronized中的锁是非公平的,ReentrantLock默认也是非公平的,但是可以通过修改参数来实现公平锁。(3)ReentrantLock绑定多个条件(4)synchronized是Java中的关键字是JV......
  • synchronized使用String做锁定互斥
    依靠ConcurrentHashMap特性,自己实现一个工厂类:importlombok.Data;importlombok.extern.slf4j.Slf4j;importorg.springframework.util.StringUtils;importjava.util.concurrent.ConcurrentHashMap;importjava.util.concurrent.ConcurrentMap;@Slf4jpublicclassMute......
  • 无涯教程-Clojure - dosync函数
    在包含表达式和任何嵌套调用的事务中运行表达式,如果没有任何线程在该线程上运行,则启动事务,任何未捕获的异常都将中止事务,并退出dosync。dosync-语法(dosyncexpression)参数   - "expression"是一组表达式,将出现在dosync块中。返回值 -无。dosync-示例以下......
  • 前端多线程处理——async/await
    async从字面上看就是“异步”,它放在函数定义之前,是使该函数在调用时开一个子线程,以不影响主线程的运行。而await经常和async组合使用,在async定义的函数中来等待需要时间运行的代码(如ajax请求、Promise对象)的运行结果,以做后续的处理。  如下面的返回Promise对象......