使用多个线程并发写入文件

标签 c linux concurrency pthreads block-device

我有一个用户级程序,它使用标志 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/

相关文章:

c - 使用专为 Vista 设计的 WinAPI 功能,同时保持与 XP 的向后兼容性?

c++ - 为什么 isalpha() 的返回类型是 int 而不是 bool?

c - C语言中指针的使用

c - 输出文件描述符重定向到管道的进程正在屏幕而不是管道上写入

linux - 使用 tar 命令时如何防止覆盖现有文件

linux - 如何在 Linux Debian Wheezy 上安装 Haskell Platform?

c - 通过管道从一个进程发送到另一个进程的缓冲区大小

ios - AFJSONRequestOperation,如果操作成功则更新 UI

c++ - 可理解的竞争条件错误导致安全漏洞

c++ - 困难的并发设计