🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
# 文件系统,第 6 部分:内存映射文件和共享内存 > 原文:<https://github.com/angrave/SystemProgramming/wiki/File-System%2C-Part-6%3A-Memory-mapped-files-and-Shared-memory> ## 操作系统如何将我的进程和库加载到内存中? 通过将文件的内容映射到进程的地址空间。如果许多程序只需要对同一文件的读访问(例如/ bin / bash,C 库),则可以在多个进程之间共享相同的物理内存。 程序可以使用相同的机制将文件直接映射到内存中 ## 如何将文件映射到内存? 将文件映射到内存的简单程序如下所示。需要注意的要点是: * mmap 需要一个 filedescriptor,所以我们需要首先`open`该文件 * 我们寻求所需的大小并写入一个字节以确保文件足够长 * 完成后调用 munmap 从内存中取消映射文件。 此示例还显示预处理器常量“ **LINE** ”和“ **FILE** ”,其中包含当前正在编译的文件的当前行号和文件名。 ```c #include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <sys/stat.h> #include <sys/mman.h> #include <fcntl.h> #include <unistd.h> #include <errno.h> #include <string.h> int fail(char *filename, int linenumber) { fprintf(stderr, "%s:%d %s\n", filename, linenumber, strerror(errno)); exit(1); return 0; /*Make compiler happy */ } #define QUIT fail(__FILE__, __LINE__ ) int main() { // We want a file big enough to hold 10 integers int size = sizeof(int) * 10; int fd = open("data", O_RDWR | O_CREAT | O_TRUNC, 0600); //6 = read+write for me! lseek(fd, size, SEEK_SET); write(fd, "A", 1); void *addr = mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); printf("Mapped at %p\n", addr); if (addr == (void*) -1 ) QUIT; int *array = addr; array[0] = 0x12345678; array[1] = 0xdeadc0de; munmap(addr,size); return 0; } ``` 我们的二进制文件的内容可以使用 hexdump 列出 ``` $ hexdump data 0000000 78 56 34 12 de c0 ad de 00 00 00 00 00 00 00 00 0000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0000020 00 00 00 00 00 00 00 00 41 ``` 细心的读者可能会注意到我们的整数是用最不重要的字节格式编写的(因为那是 CPU 的结束)并且我们分配了一个字节太多的文件! `PROT_READ | PROT_WRITE`选项指定虚拟内存保护。可以将选项`PROT_EXEC`(此处未使用)设置为允许 CPU 在内存中执行指令(例如,如果映射可执行文件或库,这将非常有用)。 ## 内存映射文件有什么好处 对于许多应用程序,主要优点是: 简化编码 - 文件数据立即可用。无需解析传入的数据并将其存储在新的内存结构中。 文件共享 - 在多个进程之间共享相同数据时,内存映射文件特别有效。 对于简单顺序处理的注意事项,内存映射文件不一定比`read` / fscanf 等标准的“基于流”的方法更快。 ## 如何在父进程和子进程之间共享内存? 简单 - 使用没有文件的`mmap` - 只需指定 MAP_ANONYMOUS 和 MAP_SHARED 选项! ```c #include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <sys/stat.h> #include <sys/mman.h> /* mmap() is defined in this header */ #include <fcntl.h> #include <unistd.h> #include <errno.h> #include <string.h> int main() { int size = 100 * sizeof(int); void *addr = mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0); printf("Mapped at %p\n", addr); int *shared = addr; pid_t mychild = fork(); if (mychild > 0) { shared[0] = 10; shared[1] = 20; } else { sleep(1); // We will talk about synchronization later printf("%d\n", shared[1] + shared[0]); } munmap(addr,size); return 0; } ``` ## 我可以为 IPC 使用共享内存吗? 是!作为一个简单示例,您可以保留几个字节,并在您希望子进程退出时更改共享内存中的值。共享内存是一种非常有效的进程间通信形式,因为没有复制开销 - 这两个进程实际上共享相同的 _ 物理 _ 内存帧。 [转到文件系统:第 7 部分](https://github.com/angrave/SystemProgramming/wiki/File-System,-Part-7:-Scalable-and-Reliable-Filesystems)