You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何获取memfd_create分配的内存地址?(父子进程共享场景)

嘿,这个需求我刚好实操过,咱们直接说解决方案——要拿到memfd对应的内存地址,核心是用mmap()把memfd描述符映射到进程的地址空间。memfd本质是内核里的匿名文件,和普通文件一样可以通过mmap映射,这样就能得到直接读写的指针了。

下面分步骤讲清楚父子进程的实现逻辑,再给你完整的代码示例:

核心思路拆解

  1. 父进程侧操作:

    • 用memfd_create()创建匿名内存文件描述符;
    • 必须用ftruncate()设置memfd的大小(初始是0,不设置的话mmap会失败);
    • 调用mmap()把memfd映射到父进程地址空间,拿到读写指针;
    • 写入共享数据后,fork子进程,用dup2()把memfd绑定到stdin(或者你指定的固定fd,方便子进程识别);
    • 子进程调用execl()启动新程序。
  2. 子进程(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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 07:11:24