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

2023-12-29

我正在使用 mmap() 快速读取大文件,将我的脚本基于这个问题的答案(C++ 快速读取文本文件 https://stackoverflow.com/questions/17925051/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() 函数的末尾,但它没有改变任何东西。

预先非常感谢您的帮助!

EDIT:

在收到重要建议后,我对 mmap() 和 std::cin() 的不同方法进行了一些性能比较,请查看:C++ 中的快速文件读取,mmap() 和 std::cin() 不同策略的比较结果解释 https://stackoverflow.com/questions/55379852/fast-file-reading-in-c-comparison-of-different-strategies-with-mmap-and-std为了结果


限制同时打开的文件数

正如您可以想象的那样,保持文件打开会消耗资源。因此,无论如何,系统上打开的文件描述符的数量都存在实际限制。这就是为什么强烈建议关闭不再需要的文件的原因。

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

mmap的特例

显然,与mmap() http://pubs.opengroup.org/onlinepubs/7908799/xsh/mmap.html你打开一个文件。正如您可能遇到的那样,在循环中重复执行此操作有迟早达到致命文件描述限制的风险。

尝试关闭文件的想法还不错。问题是它不起作用。这是在POSIX 文档 http://pubs.opengroup.org/onlinepubs/7908799/xsh/mmap.html:

The mmap()函数添加对关联文件的额外引用 带有文件描述符fildes,该描述符不会被后续操作删除close()在该文件描述符上。这个参考是存在时删除 不再有到该文件的映射.

为什么 ?因为mmap()以特殊方式将文件链接到虚拟内存管理 https://en.wikipedia.org/wiki/Virtual_memory在你的系统中。只要您使用分配给它的地址范围,就需要该文件。

那么如何删除这些映射呢?答案是使用munmap() http://pubs.opengroup.org/onlinepubs/7908799/xsh/munmap.html:

功能munmap()删除整个页面的任何映射 包含从以下位置开始的进程地址空间的任何部分 addr 并继续 len 字节。

而且当然,close()您不再需要的文件描述符。谨慎的做法是在munmap(),但原则上,至少在兼容 POSIX 的系统上,这应该不重要当你关门的时候 https://stackoverflow.com/q/17490033/3723423。不过,为了安全起见,请检查最新的操作系统文档:-)

*Note: 文件映射 https://learn.microsoft.com/en-us/windows/desktop/Memory/file-mapping也可在 Windows 上使用;这有关关闭句柄的文档 https://learn.microsoft.com/en-us/windows/desktop/Memory/closing-a-file-mapping-object如果存在剩余映射,则潜在的内存泄漏是不明确的。这就是为什么我建议在结束时刻保持谨慎。 *

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C++ 关闭使用 mmap 读取的 open() 文件 的相关文章

  • 读取大文件并制作字典

    我有一个大文件 我需要读取它并从中制作字典 我希望这一切能够尽可能快 然而我的Python代码太慢了 这是一个显示问题的最小示例 首先制作一些假数据 paste lt seq 20000000 lt seq 2 20000001 gt la
  • BufferBlock 连续

    我想使用以下方式实现消费者 生产者模式BufferBlock
  • JetBrains Rider 针对 4.5 框架,无法切换到 4.7

    基本上 当尝试添加不支持旧框架的 NuGet 包时 会出现错误 但是在项目配置中只有 4 5 可用 在项目创建过程中 不存在选择目标的选项 有什么方法可以正确配置它吗 I haven t found out how to set up NE
  • 何时使用 C++ 私有继承而不是组合?

    你能给我一个具体的例子吗 什么时候使用私有继承优于组合 就我个人而言 我将使用组合而不是私有继承 但在某些情况下 使用私有继承可能是特定问题的最佳解决方案 正在阅读C faq http www parashift com c faq lit
  • 如何部署包含第三方 DLL 文件的 C# 应用程序?

    首先 我对部署了解不多 我希望我的问题有意义 我需要将 C 应用程序安装 部署到多个桌面 它需要一个第三方 DLL 文件 一个 C 库 lpsolve55 dll 对于那些感兴趣的人 它是一个免费的 MIP LP 求解器 请参阅 lpsol
  • 如何在 ASP.NET Core 6.0 Web API 项目中启用 cors?

    在我的 ASP NET Core 6 0 Web API 项目中配置了 CORS 但预检请求收到 http 405 错误 换句话说 不允许使用 HTTP OPTION 看起来 cors 没有启用 我见过的例子config EnableCor
  • 应用新设置时如何防止 GraphicsDevice 被丢弃?

    我的游戏窗口允许手动调整大小 这意味着它可以像任何其他普通窗口一样通过拖动其边缘来调整大小 游戏还利用了RenderTarget2D rt2d 在主 Draw 方法中设置主渲染目标 GraphicsDevice SetRenderTarge
  • C#生成的csv文件通过电子邮件发送嵌入到Lotus Note中电子邮件的底部

    我遇到了一个奇怪的问题 即使用 NET SmtpClient 通过电子邮件发送的 CSV 附件出现在电子邮件底部 而不是 Lotus Note 中的附件 我只是不知道如何解决这个问题 而且我无法访问客户端计算机 这使得调试非常困难 我可以采
  • 原子的 C++ 内存屏障

    在这方面我是个新手 谁能提供以下内存屏障之间差异的简化解释 窗户MemoryBarrier 围栏 mm mfence 内联汇编asm volatile memory 内在的 ReadWriteBarrier 如果没有简单的解释 一些好文章或
  • 何时分离或加入 boost 线程?

    我有一个方法 大约每 30 秒触发一次 我需要在一个线程中包含它 我有一个可以从类外调用的方法 像 call Threaded Method 这样的东西会创建一个线程 该线程本身会调用最终的线程方法 这些是 MyClass 的方法 void
  • 文件加密与解密问题

    我一直在尝试在 VC Express 2010 中加密和解密文件 我见过的所有教程和文档都需要两个FileStreams 来加密文件 一个用于读取未加密的版本 另一个用于加密 当我实际编写代码时 它不断抛出错误 告诉我它无法打开该文件 因为
  • 如何使用 C# 将表格粘贴到 Ms-Word 文档的末尾

    我有一个预制的 Word 模板 其中有一个表格 我想打开它 然后在文档末尾添加 粘贴 另一个表格 问题是它不会转到文档的末尾 而是将新表格粘贴到原始表格的第一个单元格中 任何帮助将不胜感激 previous code copied a ta
  • 如何在 SQLite 中检查数据库是否存在 C#

    我目前正在用 C 编写一个应用程序 并使用 sqlite 作为嵌入式数据库 我的应用程序在启动时创建一个新数据库 但如何让它检查数据库是否存在 如果它确实存在 我如何让它使用它 如果不存在如何创建一个新数据库 这是我到目前为止所拥有的 pr
  • 使用 WinAPI 连接禁用的显示设备

    我的问题是启用禁用的监视器ChangeDisplaySettingsEx 我想这不是火箭科学 但经过一番挖掘后 它看起来仍然是不可能的 我找到了一种根据找到的 Microsoft 代码示例禁用所有辅助显示器的方法here https msd
  • 如何使 WinForms UserControl 填充其容器的大小

    我正在尝试创建一个多布局主屏幕应用程序 我在顶部有一些按钮链接到应用程序的主要部分 例如模型中每个实体的管理窗口 单击这些按钮中的任何一个都会在面板中显示关联的用户控件 面板包含用户控件 而用户控件又包含用户界面 WinForms User
  • 在 lua 中加载 C++ 模块时出现“尝试索引字符串值”错误

    我正在尝试使用 lua 用 C 编写的函数 下面给出的是cpp文件 extern C include lua h include lauxlib h include lualib h static int add 5 lua State L
  • 使用方法的状态模式

    我正在尝试使用方法作为状态而不是类来基于状态模式的修改版本来实现一个简单的状态机 如下所示 private Action
  • 包含从代码隐藏 (ASP.NET C#) 到 ASPX 中的图像概述的图像列表 [关闭]

    就目前情况而言 这个问题不太适合我们的问答形式 我们希望答案得到事实 参考资料或专业知识的支持 但这个问题可能会引发辩论 争论 民意调查或扩展讨论 如果您觉得这个问题可以改进并可能重新开放 访问帮助中心 help reopen questi
  • boost::spirit::qi::语法和可变参数模板

    我在使用可变参数模板定义语法时面临一个问题 我首先定义一些包含在某些结构中的简单语法 例如纬度 经度 如下所示 include
  • 线程安全的有限大小队列,不使用锁

    我正在尝试编写一个主题队列 但遇到死锁和其他多线程问题 我想用Interlocked CompareExchange避免lock用法 但这段代码并没有按预期工作 它只是擦除整个队列 我在这里做错了什么 public class FixedS

随机推荐