对 NFS 文件进行并发写入和读取操作的问题

问题描述 投票:0回答:1

我有两个进程:一个是使用 fwrite 循环写入文件,另一个是使用 read 循环读取文件。读取器进程有时会返回零字节(缓冲区中全部为零),但是当它尝试再次读取时,它工作正常。该文件位于网络文件系统 wekafs 上,读取过程发生在写入者仍在写入文件时(实时读取)。

这是阅读器进程的代码:

#include <iostream>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>

int main() {
    const char* filename = "<my file>";
    
    // Open the file for reading
    int fd = open(filename, O_DIRECT | O_RDONLY);
    if (fd < 0) {
        perror("Failed to open file for reading");
        return 1;
    }

    size_t sz = 40000;
    char *read_data;
    if (posix_memalign((void**)&read_data, 512, sz) != 0) {
        perror("Failed to allocate aligned memory");
        return 1;
    }

    bool loop = true;
    size_t total_bytes = 0;

    while (loop) {
        ssize_t bytes_read = read(fd, read_data, sz);
        if (bytes_read < 0) {
            perror("Failed to read from file");
            break;
        } else if (bytes_read == 0) {
            std::cout << "End of file reached." << std::endl;
            break;
        } else {
            total_bytes += bytes_read;
            std::cout << "Read " << bytes_read << " bytes, total so far: " << total_bytes << std::endl;
        }
    }

    // Clean up
    free(read_data);
    close(fd);

    return 0;
}

问题: 有时,当读取器尝试读取时,它会在缓冲区中得到全零,我认为这是垃圾数据。当读者再次尝试时,效果很好。 写入器不断写入文件,读取器在文件被修改的同时实时读取文件(实时读取)。 该文件位于 wekafs 网络文件系统上,我不确定问题是否与网络延迟或文件系统的缓存问题有关。

我尝试过的: 确保阅读器正确检查错误(即检查 read() 返回值)。

问题是否与网络文件系统如何处理实时读写有关,或者我在处理读写器同步时还遗漏了什么?

c++ file memory concurrency filesystems
1个回答
0
投票

这是预期的行为,至少在 Unix 下是这样。文件上的

read
函数(管道和其他源有不同的行为)是立即返回,将所有可用字节从当前位置传输到文件的当前末尾,并给出最大计数。如果当前读取位置对应于当前文件末尾,
read
将传输 0 个字节并返回 0,即使另一个程序稍后可能会写入其他字节,从而更改当前文件末尾。当然,在大多数情况下,读取文件的程序并不期望其他程序同时写入该文件,并且会将读取 0 字节视为文件结尾,但这是由应用程序和大多数库——例如,在这种情况下,
std::ifstream
将关闭文件并发出 EOF 信号。但这是应用程序或库的决定,有些程序,例如
tail -f
,即使读取了0个字节也会继续尝试读取。

因此,当编写者不会写任何其他内容时,您需要定义一些其他方法来检测真正的文件结尾。这可以通过哨兵值(例如“” EOF ") 在输入中,一些带外信号(例如发送到读取进程的信号)或简单的超时 - 如果写入进程在过去 60 秒内没有写入任何内容,比如说,我们关闭文件并在所有情况下,在读取 0 字节后重试读取之前稍微休息一下可能是个好主意。

请注意,我不太确定

O_DIRECT
在这里会产生什么影响。我希望读取的字节数始终是磁盘块大小的倍数(可能是 0),但 Linux 文档并不是很清楚——它只说它将“尝试最小化缓存影响”,所以目前尚不清楚如果编写程序不使用
O_DIRECT
会发生什么。我相当怀疑,除非编写程序也使用
O_DIRECT
,否则这是不合适的。

© www.soinside.com 2019 - 2024. All rights reserved.