我有两个过程:
进程A将大文件(~170 GB – 内容不断更改)映射到内存中,以便使用标志MAP_NONBLOCK和MAP_SHARED进行写入:
MyDataType *myDataType; = (MyDataType*)mmap(NULL, sizeof(MyDataType), PROT_WRITE, MAP_NONBLOCK | MAP_SHARED , fileDescriptor, 0);
每一秒我都会调用msync:
msync((void *)myDataType, sizeof(MyDataType), MS_ASYNC);
这部分工作正常.
当进程B尝试从进程A映射到的同一文件中读取时,问题发生,进程A没有响应约20秒.
进程B尝试使用fread()和fseek(),小块(每次约4个字节)从文件读取1000次.
该过程正在阅读的大部分内容彼此接近.
造成这个问题的原因是什么?它与页面分配有关吗?我该如何解决?
顺便说一句,当我在进程B中使用mmap()而不是简单的fread()时,会出现同样的问题.
解决方法:
msync()可能是问题所在.它强制系统写入磁盘,在写入*中阻止内核.
通常在Linux上(在Solaris BTW上也是如此),经常使用msync()是一个坏主意.没有必要调用msync()来实现内存映射和read()/ write()I / O操作之间的数据同步,这是一种来自过时的HOWTO的误解.实际上,mmap()仅使进程的文件系统缓存“可见”.这意味着内存块阻止进程更改仍在内核控制之下.即使您的进程崩溃,更改也会最终落在磁盘上.其他进程仍然可以由相同的缓冲区提供服务.
这里有关于mmap, msync and linux process termination的另一个答案
有趣的部分是关于realworldtech讨论的链接,其中Linus Torvalds自己解释了缓冲区缓存和内存映射的工作原理.
PS:fseek()/ fread()对也可能更好地被pread()取代. 1系统调用始终优于2.此外,fseek()/ fread()总是读取4K并在缓冲区中复制,因此如果您有几个没有fseek()的小读取,它将从其本地缓冲区读取并可能错过更新过程A.