在进程间通信(IPC)中,内存映射区(Memory-Mapped Area 或 Memory-Mapped File)是一种高效的通信机制,通过共享内存实现进程间的数据交换。使用内存映射区的主要优点是,它允许不同进程访问同一个物理内存区域,而不需要显式的数据拷贝。
内存映射区的概念
内存映射区是将文件或设备的内容映射到进程的虚拟内存地址空间中。进程可以像操作普通内存一样读写这些映射的区域,而这些操作会直接反映到文件或设备上。对于进程间通信,可以使用匿名内存映射区(不对应具体的文件),进程通过共享这个匿名内存区域来进行数据交换。
使用内存映射区进行进程间通信
步骤
-
创建内存映射区:
- 使用
mmap()
系统调用创建内存映射区。匿名内存映射区通常通过打开一个虚拟内存文件(如/dev/zero
)或使用shm_open()
创建。
- 使用
-
同步访问:
- 多个进程访问同一个共享内存区域时,需要使用同步机制(如信号量或互斥锁)来防止竞争条件和数据不一致。
示例代码
以下是使用内存映射区进行进程间通信的示例:
- 父子进程间共享内存:
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <sys/wait.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
int main() {
// 创建匿名内存映射区
const size_t SIZE = 4096;
void *shared_memory = mmap(NULL, SIZE, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
if (shared_memory == MAP_FAILED) {
perror("mmap");
exit(EXIT_FAILURE);
}
pid_t pid = fork();
if (pid == -1) {
perror("fork");
exit(EXIT_FAILURE);
}
if (pid == 0) { // 子进程
// 写入共享内存
const char *message = "Hello from child process!";
strcpy((char *)shared_memory, message);
// 解除内存映射区
munmap(shared_memory, SIZE);
exit(EXIT_SUCCESS);
} else { // 父进程
wait(NULL); // 等待子进程
// 读取共享内存
printf("Parent read: %s\n", (char *)shared_memory);
// 解除内存映射区
munmap(shared_memory, SIZE);
exit(EXIT_SUCCESS);
}
}
代码解析
-
创建内存映射区:
void *shared_memory = mmap(NULL, SIZE, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
mmap()
用于创建一个匿名内存映射区。MAP_SHARED
标志表示这个映射区可以在多个进程间共享。MAP_ANONYMOUS
标志表示这个映射区不与任何文件关联。
-
进程间通信:
- 父进程使用
fork()
创建子进程。 - 子进程在共享内存区域写入数据。
- 父进程等待子进程结束,然后从共享内存区域读取数据。
- 父进程使用
-
解除内存映射:
munmap(shared_memory, SIZE);
- 使用
munmap()
解除内存映射区,释放资源。
- 使用
使用 shm_open
和 mmap
shm_open
和 mmap
可以结合使用,创建命名共享内存区域,使无亲缘关系的进程间通信变得可能。
以下是使用 shm_open
和 mmap
的示例:
-
进程A(创建和写入共享内存):
#include <stdio.h> #include <stdlib.h> #include <sys/mman.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #include <string.h> int main() { const char *name = "/my_shm"; const size_t SIZE = 4096; int shm_fd = shm_open(name, O_CREAT | O_RDWR, 0666); if (shm_fd == -1) { perror("shm_open"); exit(EXIT_FAILURE); } if (ftruncate(shm_fd, SIZE) == -1) { perror("ftruncate"); exit(EXIT_FAILURE); } void *shared_memory = mmap(0, SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0); if (shared_memory == MAP_FAILED) { perror("mmap"); exit(EXIT_FAILURE); } const char *message = "Hello from process A!"; strcpy((char *)shared_memory, message); munmap(shared_memory, SIZE); close(shm_fd); return 0; }
-
进程B(读取共享内存):
#include <stdio.h> #include <stdlib.h> #include <sys/mman.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #include <string.h> int main() { const char *name = "/my_shm"; const size_t SIZE = 4096; int shm_fd = shm_open(name, O_RDONLY, 0666); if (shm_fd == -1) { perror("shm_open"); exit(EXIT_FAILURE); } void *shared_memory = mmap(0, SIZE, PROT_READ, MAP_SHARED, shm_fd, 0); if (shared_memory == MAP_FAILED) { perror("mmap"); exit(EXIT_FAILURE); } printf("Read from shared memory: %s\n", (char *)shared_memory); munmap(shared_memory, SIZE); close(shm_fd); shm_unlink(name); return 0; }
代码解析
-
创建和写入共享内存:
shm_open
创建或打开一个命名共享内存对象。ftruncate
设置共享内存对象的大小。mmap
将共享内存对象映射到进程的地址空间。- 写入数据到共享内存。
-
读取共享内存:
shm_open
以只读模式打开命名共享内存对象。mmap
将共享内存对象映射到进程的地址空间。- 读取数据。
-
清理:
- 使用
munmap
解除内存映射。 - 使用
close
关闭文件描述符。 - 使用
shm_unlink
删除命名共享内存对象。
- 使用
通过内存映射区进行进程间通信,可以实现高效的共享内存访问,这对于需要频繁且高速的数据交换的应用非常有用。
标签:共享内存,映射,--,用户区,内存,shared,include,shm From: https://www.cnblogs.com/whcjob/p/18205745