gpt4 book ai didi

c++ - 文件 read() 卡在二进制大文件上

转载 作者:塔克拉玛干 更新时间:2023-11-03 00:04:41 25 4
gpt4 key购买 nike

我正在研究一个基准程序。在制作 read()系统调用,程序似乎无限期挂起。目标文件是 1 GB 的二进制数据,我试图直接读入大小为 1、10 或 100 MB 的缓冲区。

我正在使用 std::vector<char>实现动态大小的缓冲区和移交 &vec[0]read() .我也在打电话 open()O_DIRECT绕过内核缓存的标志。

基本编码细节如下:

std::string fpath{"/path/to/file"};
size_t tries{};
int fd{};
while (errno == EINTR && tries < MAX_ATTEMPTS) {
fd = open(fpath.c_str(), O_RDONLY | O_DIRECT | O_LARGEFILE);
tries++;
}

// Throw exception if error opening file
if (fd == -1) {
ostringstream ss {};
switch (errno) {
case EACCES:
ss << "Error accessing file " << fpath << ": Permission denied";
break;
case EINVAL:
ss << "Invalid file open flags; system may also not support O_DIRECT flag, required for this benchmark";
break;
case ENAMETOOLONG:
ss << "Invalid path name: Too long";
break;
case ENOMEM:
ss << "Kernel error: Out of memory";
}
throw invalid_argument {ss.str()};
}

size_t buf_sz{1024*1024}; // 1 MiB buffer
std::vector<char> buffer(buf_sz); // Creates vector pre-allocated with buf_sz chars (bytes)
// Result is 0-filled buffer of size buf_sz

auto bytes_read = read(fd, &buffer[0], buf_sz);

用 gdb 查看可执行文件显示缓冲区分配正确,我测试过的文件在 xxd 中 check out 。我正在使用 g++ 7.3.1(支持 C++11)在 Fedora Server 27 VM 上编译我的代码。

为什么是read()卡在大型二进制文件上?编辑:更新代码示例以更准确地反射(reflect)错误检查。

最佳答案

您的代码存在多个问题。

如果 errno 的值等于 EINTR,此代码将永远无法正常工作:

while (errno == EINTR && tries < MAX_ATTEMPTS) {
fd = open(fpath.c_str(), O_RDONLY | O_DIRECT | O_LARGEFILE);
tries++;
}

该代码不会在文件成功打开后停止,并且会一遍又一遍地重新打开文件并泄漏文件描述符,因为它会在 errnoEINTR 时不断循环>.

这样会更好:

do
{
fd = open(fpath.c_str(), O_RDONLY | O_DIRECT | O_LARGEFILE);
tries++;
}
while ( ( -1 == fd ) && ( EINTR == errno ) && ( tries < MAX_ATTEMPTS ) );

其次,如评论中所述,O_DIRECT 可以对内存施加对齐限制。您可能需要页面对齐的内存:

所以

size_t buf_sz{1024*1024};          // 1 MiB buffer
std::vector<char> buffer(buf_sz); // Creates vector pre-allocated with buf_sz chars (bytes)
// Result is 0-filled buffer of size buf_sz

auto bytes_read = read(fd, &buffer[0], buf_sz);

成为

size_t buf_sz{1024*1024};          // 1 MiB buffer

// page-aligned buffer
buffer = mmap( 0, buf_sz, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, NULL );

auto bytes_read = read(fd, &buffer[0], buf_sz);

另请注意 O_DIRECT 的 Linux 实现可能非常不可靠。它变得越来越好,但仍然存在根本没有很好记录的潜在陷阱。除了对齐限制外,如果文件中的最后一个数据量不是整页,例如,如果文件系统的直接 IO 实现不允许您读取整页以外的任何内容,您可能无法读取它(或其他一些 block 大小)。同样对于 write() 调用 - 您可能无法写入任意数量的字节,您可能会被限制为 4k 页面。

这也很关键:

Most examples of read() hanging appear to be when using pipes or non-standard I/O devices (e.g., serial). Disk I/O, not so much.

有些设备根本不支持直接 IO。它们应该会返回一个错误,但再次强调,Linux 上的 O_DIRECT 实现可能非常偶然。

关于c++ - 文件 read() 卡在二进制大文件上,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49434527/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com