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

UNIX C中“反向mmap”实现:地址空间映射至文件系统无需写入磁盘

替代临时磁盘文件的内存共享方案

你要的“反向mmap”本质是让程序B能像读取普通文件一样访问父进程的内存空间,同时避免磁盘IO和临时文件残留。以下是几种实用技术方案:

1. 利用 /dev/shm 内存文件系统

/dev/shm 是基于内存的临时文件系统,写入这里的文件不会落到磁盘,重启后自动消失。父进程可以在这里创建文件并映射到自身地址空间,程序B直接读取该文件路径即可。

实现步骤:

  • 父进程在 /dev/shm 创建文件:int fd = open("/dev/shm/my_temp_file", O_RDWR | O_CREAT | O_EXCL, 0600);
  • 将文件映射到父进程内存:char *buf = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
  • 写入数据到 buf,然后通知程序B读取 /dev/shm/my_temp_file
  • 程序B读取完成后,父进程删除文件:unlink("/dev/shm/my_temp_file");

优点:

  • 实现简单,程序B无需修改,直接读普通文件路径
  • 无磁盘IO开销

缺点:

  • 需要处理文件命名冲突问题
  • 依赖系统挂载的 /dev/shm(大部分Linux系统默认挂载)

2. memfd_create + UNIX域套接字传递文件描述符

memfd_create 可以创建匿名的内存文件描述符(无文件系统路径),父进程将其映射到自身内存写入数据,再通过UNIX域套接字把这个fd传递给程序B,程序B直接读该fd即可,完全不需要文件系统路径。

代码示例(C语言):

#include <sys/memfd.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/wait.h>

int main() {
    // 创建匿名内存文件
    int memfd = memfd_create("shared_data", MFD_CLOEXEC);
    if (memfd == -1) { perror("memfd_create"); return 1; }

    const size_t data_size = 4096;
    // 扩展内存文件大小
    if (ftruncate(memfd, data_size) == -1) { perror("ftruncate"); return 1; }

    // 映射到父进程地址空间,写入数据
    char *mem_buf = mmap(NULL, data_size, PROT_READ | PROT_WRITE, MAP_SHARED, memfd, 0);
    if (mem_buf == MAP_FAILED) { perror("mmap"); return 1; }
    strncpy(mem_buf, "Data from parent's address space", data_size);

    // 创建UNIX域套接字对,用于传递fd
    int sock_pair[2];
    if (socketpair(AF_UNIX, SOCK_STREAM, 0, sock_pair) == -1) { perror("socketpair"); return 1; }

    pid_t b_pid = fork();
    if (b_pid == 0) {
        // 子进程模拟程序B:接收fd并读取数据
        close(sock_pair[0]);
        int received_fd;
        char dummy;
        struct msghdr msg = {0};
        struct iovec iov = {&dummy, 1};
        msg.msg_iov = &iov;
        msg.msg_iovlen = 1;

        char ctrl_buf[CMSG_SPACE(sizeof(int))];
        msg.msg_control = ctrl_buf;
        msg.msg_controllen = sizeof(ctrl_buf);

        if (recvmsg(sock_pair[1], &msg, 0) == -1) { perror("recvmsg"); return 1; }

        struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg);
        if (cmsg && cmsg->cmsg_type == SCM_RIGHTS) {
            received_fd = *(int *)CMSG_DATA(cmsg);
            char read_buf[data_size];
            read(received_fd, read_buf, data_size);
            printf("Program B read: %s\n", read_buf);
            close(received_fd);
        }

        close(sock_pair[1]);
        return 0;
    } else {
        // 父进程:发送fd
        close(sock_pair[1]);
        struct msghdr msg = {0};
        char dummy = 'a';
        struct iovec iov = {&dummy, 1};
        msg.msg_iov = &iov;
        msg.msg_iovlen = 1;

        char ctrl_buf[CMSG_SPACE(sizeof(int))];
        msg.msg_control = ctrl_buf;
        msg.msg_controllen = sizeof(ctrl_buf);

        struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg);
        cmsg->cmsg_level = SOL_SOCKET;
        cmsg->cmsg_type = SCM_RIGHTS;
        cmsg->cmsg_len = CMSG_LEN(sizeof(int));
        *(int *)CMSG_DATA(cmsg) = memfd;

        if (sendmsg(sock_pair[0], &msg, 0) == -1) { perror("sendmsg"); return 1; }

        waitpid(b_pid, NULL, 0);
        close(memfd);
        close(sock_pair[0]);
        munmap(mem_buf, data_size);
        return 0;
    }
}

优点:

  • 完全无文件系统痕迹,不会残留临时文件
  • 效率最高,直接在内存间传递数据
  • 避免命名冲突

缺点:

  • 程序B需要支持通过UNIX套接字接收文件描述符,或者由父进程fork启动程序B

3. 共享内存 + FUSE 用户态文件系统

如果必须让程序B通过普通文件路径访问父进程内存,可以用FUSE实现一个极简的用户态文件系统,将父进程的共享内存段映射为文件。程序B读取该文件时,FUSE内核模块会直接从共享内存读取数据。

实现思路:

  • 父进程创建共享内存段:int shm_fd = shm_open("/my_shm", O_RDWR | O_CREAT, 0600);,并映射到自身内存写入数据
  • 编写FUSE文件系统代码,将/my_fuse_mount/data路径关联到该共享内存段
  • 挂载FUSE文件系统到某个目录,程序B直接读取/my_fuse_mount/data即可
  • 程序B完成后,卸载FUSE文件系统并删除共享内存段

优点:

  • 程序B无需任何修改,完全像读普通文件一样访问
  • 完全避免磁盘IO

缺点:

  • 需要编写FUSE文件系统代码,实现复杂度较高
  • 依赖FUSE内核模块(大部分Linux系统默认支持)

内容的提问来源于stack exchange,提问作者user22925547

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 15:33:14