c ++关闭用mmap读取的open()文件

c++ close a open() file read with mmap

我正在使用 mmap() 快速读取大文件,我的脚本基于这个问题的答案 (Fast textfile reading in c++)。

我正在使用 sehe 答案的第二个版本:

#include <algorithm>
#include <iostream>
#include <cstring>

// for mmap:
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>

const char* map_file(const char* fname, size_t& length);

int main()
{
    size_t length;
    auto f = map_file("test.cpp", length);
    auto l = f + length;

    uintmax_t m_numLines = 0;
    while (f && f!=l)
        if ((f = static_cast<const char*>(memchr(f, n, l-f))))
            m_numLines++, f++;

    std::cout << "m_numLines = " << m_numLines << "n";
}

void handle_error(const char* msg) {
    perror(msg);
    exit(255);
}

const char* map_file(const char* fname, size_t& length)
{
    int fd = open(fname, O_RDONLY);
    if (fd == -1)
        handle_error("open");

    // obtain file size
    struct stat sb;
    if (fstat(fd, &sb) == -1)
        handle_error("fstat");

    length = sb.st_size;

    const char* addr = static_cast<const char*>(mmap(NULL, length, PROT_READ, MAP_PRIVATE, fd, 0u));
    if (addr == MAP_FAILED)
        handle_error("mmap");

    // TODO close fd at some point in time, call munmap(...)
    return addr;
}

而且效果很好。

但是如果我通过几个文件的循环实现它(我只是将 main() 函数名称更改为:

void readFile(std::string &nomeFile) {

然后在 main() 函数中获取 "f" 对象中的文件内容:

size_t length;
auto f = map_file(nomeFile.c_str(), length);
auto l = f + length;

并在文件名列表的循环中从 main() 调用它),过了一会儿我得到:

open: Too many open files

我想有一种方法可以在处理文件后关闭 open() 调用,但我无法弄清楚如何以及将其放置在何处。我试过了:

int fc = close(fd);

在 readFile() 函数的末尾,但它没有任何改变。

非常感谢您的帮助!

编辑:

在收到重要建议后,我用 mmap() 和 std::cin() 对不同方法进行了一些性能比较,查看:fast file reading in C++, comparison of different strategies with mmap() and std::cin() results interpretation 结果

同时打开文件数限制

如您所想,保持文件打开会消耗资源。因此,在任何情况下,系统上打开的文件描述符的数量都有一个实际限制。这就是为什么强烈建议您关闭不再需要的文件的原因。

确切的限制取决于 OS 和配置。如果你想了解更多,这类问题已经有很多答案了。

mmap 的特例

显然,使用 mmap() 您可以打开一个文件。并且在循环中重复这样做迟早会达到致命的文件描述限制,正如您可能遇到的那样。

尝试关闭文件的想法不错。问题是它不起作用。这在 POSIX documentation 中指定:

The mmap() function adds an extra reference to the file associated with the file descriptor fildes which is not removed by a subsequent close() on that file descriptor. This reference is removed when there are no more mappings to the file.

为什么?因为 mmap() 以特殊方式将文件链接到系统中的 virtual memory management。只要您使用分配给它的地址范围,就需要这个文件。

那么如何删除那些映射呢?答案是使用 munmap():

The function munmap() removes any mappings for those entire pages containing any part of the address space of the process starting at addr and continuing for len bytes.

当然,close() 您不再需要的文件描述符。谨慎的做法是在 munmap() 之后关闭,但原则上,至少在 POSIX 兼容系统上,when you're closing 应该无关紧要。不过,请检查您最新的 OS 文档以确保安全:-)

*注意:如果有剩余映射, file mapping is also available on windows; the documentation about closing the handles 对潜在的内存泄漏不明确。这就是为什么我建议在收盘时谨慎行事。 *