关于write()和fsync()

时间:2021-10-13 15:22:08

--关于write()和fsync()  

----------------------------转载

write

ssize_t write(int fd, const void *buf, size_t count);

将数据写到文件中. 注意, 如果文件是保存在硬盘中, write() 函数调用返回之后, 并不表示数据已经写入到硬盘中, 这时如果掉电, 数据可能会丢失.

fsync

int fsync(int fd);

程序调用本函数, 通知内核把数据写到硬盘(file)中. 比如, 你开发一个数据库软件, 就需要这样的函数, 否则掉电或者系统崩溃时便会丢失数据.

如果你的程序不调用 fsync(), Linux 内核也会自动在”合适”的时候将你的数据真正写入到硬盘(类似调用 fsync), 最长的延时默认是 30 秒.

阻塞

阻塞是 IO 的精华所在, 不管是文件 IO 还是网络 IO, 只有真正了理解了 IO 阻塞, 才能做出所谓在高并发高性能软件(服务器).

当 fsync() 和 write() 同一个 fd 时, write() 必然阻塞. 当系统 IO 非常繁忙时, fsync() 可能会阻塞, 即使系统 IO 不繁忙, fsync() 也会因为数据量大而慢.

注: 许多 Linux 系统函数如 read(), write() 等, 粗看起来很简单, 也很容易用. 正如所有的事情一样, 要做到精致肯定不简单. 当你脱离初级的学习阶段, 要写真正生产环境的软件时, 这些”简单”的函数就大有门道了. 你需要不断的阅读它们的手册, 了解每一个参数, 每一个返回值, 同时还要阅读和试验在各种条件和环境下这些函数的表现, 这样, 才有可能做出真正的软件.

关于write()和fsync()

楼主password636(亮)2006-03-02 18:08:38 在 Linux/Unix社区 / 程序开发区 提问

关于linux系统调用write()   
  调用一次write()完毕,是不是已经写到磁盘上了?   
  是不是调用一次write(),就是一次写请求,不管写多少个字符进去,调用完都已经通过缓冲区写到磁盘上了?   
  那么fsync()这个函数是不是指将缓冲区的写到磁盘上,如果是,write完再fsync是不是多此一举?   
  我想实现的是可以先创建一个文件,然后写一些东西到该文件的缓冲区,再调用fsync()写入磁盘,请问如何实现?   
  问题点数:10、回复次数:7Top

1 楼morpheus1977()回复于 2006-03-03 22:07:46 得分 0

write()   是不带缓存的。   应该不用吧。Top

2 楼tb01412(tb)回复于 2006-03-03 22:49:08 得分 0

所谓write不带缓存是指不在C库中缓存,只要应用层调用write,就直接发出write系统调用,而内核中的write块设备都是有缓存的,所以就需要fsync将磁盘高速缓冲中的数据立刻写入磁盘中去!!!!!Top

3 楼password636(亮)回复于 2006-03-04 12:32:50 得分 0

但是为什么我write()完后,用stat()输出st_size,就是写入的个数呢?要是有缓存,应该是0啊?Top

4 楼tb01412(tb)回复于 2006-03-04 13:11:31 得分 10

呵呵,当你用write之后,内核就响应write系统调用,然后向高速磁盘缓冲块写入数据,之后,你如果用stat,或者read时,系统首先会在高速缓冲块中去查看相应的数据是否在块中,如果不是,然后再调用磁盘驱动加载磁盘数据到高速缓冲块中,然后再由高速缓冲块中返回你要的数据!!!!!这就是你用stat()输出st_size,就是写入的个数的原因!!!!!   
  系统会在合适的时机再向真正的硬件写入高速缓冲块中的数据,也可以用fsync强制把高速缓冲块中的相应数据写入磁盘!!!!!!!Top

5 楼password636(亮)回复于 2006-03-05 18:31:56 得分 0

如何能证明fsync()是强制从缓存写到磁盘上的?   
  我开始想证明fsync()是这样打算的,用open()创建一个文件,用write()写,然后用stat()获得一个size,之后调用fsync(),调用完后再用stat()获得一次size,开始由于对stat()的不理解,觉得stat()是从磁盘上读大小,第一次读应该是0,第二次即fsync()后读应该是write()进去的大小,可现在知道了stat()和read()都是从缓存中获得数据,那么有没有其他的办法在write()后fsync()前获得文件在磁盘上的大小?如果获得不了,那有什么办法能证明fsync()是从缓存强制写到磁盘上的?Top

6 楼tb01412(tb)回复于 2006-03-06 13:05:56 得分 0

如果只想证明fsync()是从缓存强制写到磁盘上的话,很简单:   
  使用U盘,你先向上面写入大量的数据(比如几十M),接着程序退出,然后马上拔出U盘(不要用umount),之后再将U盘插入,mount上去,然后再读出原来的文件内容,估计文件最后的内容不再是你原来写入的内容了!!!!   
    
  还有一种办法:   
  不通过磁盘缓冲读取数据,比如你想读sda1上的文件数据,直接用open("/dev/sda1"),而不再用实际文件目录的方式来操作,不过这样你需要自己去解析相应文件系统在磁盘上的物理组织格式才行Top

7 楼fgmIsdn()回复于 2006-03-09 15:37:43 得分 0

缓冲区有多个层次,OS内核肯定有,驱动程序也可能有,而且现在流行的硬盘驱动器上也有。   
  fsync()一般不要使用,立即写入硬盘磁介质上,会产生很多次写入动作,有损硬盘寿命,硬盘的性能也会收到影响。   
    
  硬盘涉及到比较复杂的技术。   
  目前IDE硬盘从2MB缓存向8MB缓存过渡,大容量有16MB的。