如何获取memfd_create分配的内存地址?(父子进程共享场景)
嘿,这个需求我刚好实操过,咱们直接说解决方案——要拿到memfd对应的内存地址,核心是用mmap()把memfd描述符映射到进程的地址空间。memfd本质是内核里的匿名文件,和普通文件一样可以通过mmap映射,这样就能得到直接读写的指针了。
下面分步骤讲清楚父子进程的实现逻辑,再给你完整的代码示例:
核心思路拆解
父进程侧操作:
- 用
memfd_create()创建匿名内存文件描述符; - 必须用
ftruncate()设置memfd的大小(初始是0,不设置的话mmap会失败); - 调用
mmap()把memfd映射到父进程地址空间,拿到读写指针; - 写入共享数据后,fork子进程,用
dup2()把memfd绑定到stdin(或者你指定的固定fd,方便子进程识别); - 子进程调用
execl()启动新程序。
- 用
子进程(execl启动的程序)侧操作:
- 从stdin(或绑定的fd)拿到memfd;
- 同样调用
mmap()把memfd映射到子进程地址空间,得到指针后直接读写。
完整代码示例
父进程代码(parent.c)
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/mman.h> #include <sys/syscall.h> #include <fcntl.h> #include <sys/wait.h> #define MEMFD_NAME "shared_mem" #define MEM_SIZE 4096 // 按需求调整大小,建议是页大小的整数倍 int main() { // 创建memfd,MFD_CLOEXEC可选:如果设置,execl时会关闭原fd,但我们dup到stdin了,不影响 int memfd = syscall(SYS_memfd_create, MEMFD_NAME, 0); if (memfd == -1) { perror("memfd_create failed"); exit(EXIT_FAILURE); } // 关键:设置memfd的大小,否则mmap会失败 if (ftruncate(memfd, MEM_SIZE) == -1) { perror("ftruncate failed"); close(memfd); exit(EXIT_FAILURE); } // 映射memfd到父进程地址空间,MAP_SHARED确保修改同步到内核 char *shared_ptr = mmap(NULL, MEM_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, memfd, 0); if (shared_ptr == MAP_FAILED) { perror("mmap failed"); close(memfd); exit(EXIT_FAILURE); } // 直接用指针写入共享数据 snprintf(shared_ptr, MEM_SIZE, "Hello from parent process! PID: %d", getpid()); printf("Parent process wrote: %s\n", shared_ptr); pid_t pid = fork(); if (pid == -1) { perror("fork failed"); munmap(shared_ptr, MEM_SIZE); close(memfd); exit(EXIT_FAILURE); } if (pid == 0) { // 子进程:将memfd绑定到stdin(fd=0) if (dup2(memfd, STDIN_FILENO) == -1) { perror("dup2 failed"); exit(EXIT_FAILURE); } close(memfd); // 原fd可以关闭,stdin已经关联了memfd // 启动子进程程序,这里替换成你的实际程序路径 execl("./child_proc", "child_proc", NULL); // execl失败才会执行到这里 perror("execl failed"); exit(EXIT_FAILURE); } else { // 父进程等待子进程完成 wait(NULL); // 验证子进程是否修改了数据 printf("Parent process read after child: %s\n", shared_ptr); // 清理资源 munmap(shared_ptr, MEM_SIZE); close(memfd); } return 0; }
子进程程序代码(child_proc.c)
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/mman.h> #include <fcntl.h> #define MEM_SIZE 4096 // 和父进程保持一致 int main() { // 从stdin拿到父进程传递过来的memfd int memfd = STDIN_FILENO; // 映射memfd到子进程地址空间 char *shared_ptr = mmap(NULL, MEM_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, memfd, 0); if (shared_ptr == MAP_FAILED) { perror("mmap failed"); close(memfd); exit(EXIT_FAILURE); } // 直接用指针读取共享数据 printf("Child process read: %s\n", shared_ptr); // 直接修改数据,父进程能同步看到 snprintf(shared_ptr, MEM_SIZE, "Hello from child process! PID: %d", getpid()); // 清理资源 munmap(shared_ptr, MEM_SIZE); close(memfd); return 0; }
关键注意事项
- memfd大小必须设置:memfd初始大小为0,不调用
ftruncate()设置大小的话,mmap会返回MAP_FAILED。 - MAP_SHARED参数:一定要用
MAP_SHARED而不是MAP_PRIVATE,否则修改只会在当前进程生效,无法同步到其他进程。 - 文件描述符继承:如果父进程创建memfd时设置了
MFD_CLOEXEC,execl会关闭原fd,但我们已经通过dup2()绑定到stdin,stdin默认不会被关闭,所以不影响。 - 内存同步:默认情况下,
MAP_SHARED的写操作会自动同步到内核,其他进程映射后能立刻看到修改。如果需要强制同步,可以调用msync(shared_ptr, MEM_SIZE, MS_SYNC)。
这样就能实现父子进程通过memfd直接用指针读写共享内存了,完全不需要用read/write接口。
内容的提问来源于stack exchange,提问作者Igor Liferenko
相关产品推荐
相关产品推荐

