我有一个用户级程序,它使用标志 O_WRONLY|O_SYNC
打开一个文件。该程序创建了 256 个线程,每个线程尝试将 256 个或更多字节的数据写入文件。我想要总共有 1280000 个请求,使其总共有大约 300 MB 的数据。一旦完成 1280000 个请求,程序就会结束。
我使用 pthread_spin_trylock()
来递增一个变量,该变量跟踪已完成的请求数。为确保每个线程写入唯一的偏移量,我使用 pwrite()
并将偏移量计算为已写入请求数的函数。因此,我在实际写入文件时不使用任何互斥锁(这种方法是否确保数据完整性?)
当我检查 pwrite()
调用被阻塞的平均时间和相应的数字(即平均 Q2C 时间——这是对整个生命周期时间的度量使用 blktrace
找到的 BIO) ,我发现有显着差异。事实上,给定 BIO 的平均完成时间远大于 pwrite()
调用的平均延迟时间。这种差异背后的原因是什么?这些数字不应该相似吗,因为 O_SYNC
确保数据在返回之前实际写入物理介质?
最佳答案
pwrite()
应该是原子的,所以你在那里应该是安全的......
关于您的系统调用和实际 BIO 之间的延迟差异,根据 man-pages at kernel.org 上的信息对于打开(2):
POSIX provides for three different variants of synchronized I/O, corresponding to the flags O_SYNC, O_DSYNC, and O_RSYNC. Currently (2.6.31), Linux only implements O_SYNC, but glibc maps O_DSYNC and O_RSYNC to the same numerical value as O_SYNC. Most Linux file systems don't actually implement the POSIX O_SYNC semantics, which require all metadata updates of a write to be on disk on returning to userspace, but only the O_DSYNC semantics, which require only actual file data and metadata necessary to retrieve it to be on disk by the time the system call returns.
因此,这基本上意味着使用 O_SYNC
标志,您尝试写入的全部数据不需要在系统调用返回之前刷新到磁盘,而只需提供足够的信息即可能够从磁盘检索它...取决于您正在编写的内容,这可能比您打算写入磁盘的整个数据缓冲区少很多,因此实际写入所有数据的处理将在稍后的时间发生,在系统调用完成并且进程转移到其他事情之后。
关于使用多个线程并发写入文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7182785/