我问了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 write
, HERE 和 ./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),那么你有两个重叠的问题:
- 您没有检查
mmap
的返回值(即使启用了assert
,它也没有被正确检查;mmap
的错误返回是MAP_FAILED
,而不是NULL
) - 你永远不会
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/