c++ - 部分文本上的并发 mmap()

标签 c++ multithreading mmap memory-mapped-files

我问了this关于如何从偏移量 pos 开始读取文本文件的问题抵消 end通过mmap() .特别是文本文件由多线程使用以下代码读取:

void getNextKeyValue() {
    key = pos;//value is the actual file offset
    char *mmappedData = (char*) mmap(NULL, end-pos+1, PROT_READ, MAP_PRIVATE , fd, pos);
    assert(mmappedData != NULL);
    value.assign(mmappedData);
    assert(munmap(mmappedData, end-pos+1)==0);
    morePairs = false;
}

未报告的变量在别处声明和初始化。什么 顺便说一下,下面的代码读取整个 文本文件,而不是从偏移量 pos 读取至 end .

上瘾时,程序在多个线程中突然终止(没有错误输出),而在只有一个线程读取整个文件时正确终止。

更新:

正在关注 this示例(您可以尝试我的版本,使用 cout insted writeHERE./main main.cpp 10 20 )我发现我做错了是我通过 cout<<mmappedData<<endl 打印了读取数据.如果我使用 write(STDOUT_FILENO, mmappedData+pos-pa_offset, end-pos);打印文本的右侧部分。

我仍然不明白的是为什么整个文本存储在mmappedData 中(或 addr 在链接示例之后):mmap用法明确指出读取的字节数是从第 4 个 arg 开始的第 2 个 arg。

最佳答案

新信息更新:

你的问题是你误解了如何mmap作品。 mmap映射内存页面,而不是字节;即使您只要求映射 24 个字节,它实际上也会映射几千字节(在大多数系统上为 4KB),并且不能保证数据是 NUL。终止(事实上,除非映射到达文件末尾,否则对于文本输入文件,它可能不会 NUL 终止)。和 std::string::assign只需要 char * 的方法因为参数使用的是 C 风格的字符串逻辑;它只是不断地读取字符,直到遇到 NUL。 .如果你“幸运”,mmap 之后的页面可读并包含一个 NUL它只是复制直到NUL的所有内容到字符串中(或等效地在执行 cout << mmappedData 时,将其写出),如果不是,则您在映射后尝试访问未映射的内存地址时出现段错误。

如果目标是将特定数量的字节分配给 std::string来自char* ,您需要使用 assign 的双参数形式像使用 write 一样使开始和长度明确,那么它只会使用你需要的数据:

value.assign(mmappedData+pos-pa_offset, end-pos);

原始推测性答案:

给出的代码不够清晰,无法排除其他问题,但如果您经常重新读取值,并且 NDEBUG设置(禁用 assert s),那么你有两个重叠的问题:

  1. 您没有检查 mmap 的返回值(即使启用了 assert,它也没有被正确检查;mmap 的错误返回是 MAP_FAILED,而不是 NULL)
  2. 你永远不会munmap -ing; munmap调用在 assert 内, 和 assert如果被禁用,您断言的代码将被预处理器删除。

所以如果你有大量的线程一遍又一遍地调用这个函数(特别是如果被映射的区域很大),你最终会耗尽虚拟内存空间;如果每次调用映射 1 MB,即使在 64 位系统(实际上只有 47 位用户模式虚拟地址空间)上,您也会在 ~134M 次调用后用完虚拟地址空间。如果每次调用都映射 1 GB,那么在约 134K 次调用后就会用完。当然,在 32 位系统上,您会更快地达到极限。

除此之外,我无从得知是否还有其他问题; value.assign如果是共享数据,也很容易成为问题。

关于c++ - 部分文本上的并发 mmap(),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34501100/

相关文章:

python - 如何在 kivy-python 中使用带多线程的时钟对象更新进度条?

c# - .NET ParameterizedThreadStart 错误的返回类型

linux - 如何使用 memmap crate 附加到文件支持的 mmap?

c++ - 通过删除最后一个参数在 C++ 中将 for(a;b;c) 简化为 for(x;y;)

c++ - 如何匿名声明 std::thread?

c++ - 如何直接删除或替换文件中的单词

java - 仅使用本地锁从 BST 进行多线程删除

c - 为什么 mmap() 比顺序 IO 快?

linux - 在哪里可以找到 mmap(系统调用)的源代码?

c++ - 将 double* 转换为 float*