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

Linux下多进程shm_open共享内存失败问题排查求助

共享内存跨进程访问问题排查

我用pthread编写了3个多线程程序,它们需要访问同一块共享内存:parent程序负责创建共享内存,另外两个是child程序。目前parent内部的两个线程(一个调用cond_wait、一个执行广播)协作正常,但把cond_wait线程的代码移植到child程序后无法正常运行。经排查确认child无法正确访问共享内存,推测问题出在父子进程创建/打开共享内存的代码实现上。


Parent 创建共享内存的代码

bool create_shared_object( shared_memory_t* shm) {
    const char* share_name = shared_memory_name;
    shm_unlink(share_name);
    shm->name = share_name;

    shm->fd = shm_open(shm->name, O_CREAT | O_EXCL  | O_RDWR, S_IRWXU | S_IRWXG | S_IRWXO);    

    if(shm->fd == -1){
        fprintf(stderr, "shm_open(%s): %s (%d)\n", shm->name, strerror(errno), errno);

        return false;
    }

    if (ftruncate(shm->fd , MEMORY_SIZE)){
        fprintf(stderr, "ftruncate(%s): %s (%d)\n", shm->name, strerror(errno), errno);

        return false;
    }

    shm = mmap(NULL, MEMORY_SIZE,
        PROT_WRITE | PROT_READ, MAP_SHARED, shm->fd, 0);
    if (shm == MAP_FAILED){
        fprintf(stderr, "mmap(%s, %zu): %s (%d)\n", shm->name, (size_t)MEMORY_SIZE, strerror(errno), errno);

        return false;     
    }   
    return true;
}

Child 打开共享内存的代码

bool create_shared_object( shared_memory_t* shm) {
    const char* share_name = shared_memory_name;

    shm->name = share_name;

    shm->fd = shm_open(shm->name, O_RDWR, 0);
    if(shm->fd == -1){
        fprintf(stderr, "shm_open(%s): %s (%d)\n", shm->name, strerror(errno), errno);

        return false;
    }
    

    shm = mmap(NULL, MEMORY_SIZE,
        PROT_WRITE | PROT_READ, MAP_SHARED, shm->fd, 0);
    if (shm == MAP_FAILED){
        fprintf(stderr, "mmap(%s, %zu): %s (%d)\n", shm->name, (size_t)MEMORY_SIZE, strerror(errno), errno);

        return false;
    }

    return true;
}

shared_memory_t 结构体定义

typedef struct shm{
    const char* name;

    int fd;

    shared_parking_t data;
}shared_memory_t;

其他相关信息

  • 每个文件中定义共享内存对象:shared_memory_t shm;
  • 执行ls -l /dev/shm显示对应的内存文件:
    -rwxr-xr-x 1 cab403 cab403 584 Sep 26 23:27 PARKING
    
  • 测试方式:通过循环打印parent修改的内存值验证child是否能访问共享内存,已根据之前的建议更新过代码,仍无法解决。
  • 操作系统:Linux

问题根源与修复方案

核心问题1:mmap操作未正确映射到外部结构体

你的create_shared_object函数中,将mmap返回的地址赋值给了函数参数shm——这是值传递的错误用法。函数内部修改的只是局部指针副本,外部的shared_memory_t shm变量根本没有被映射到共享内存区域,函数结束后修改完全丢失。

核心问题2:共享内存大小与结构体不匹配

ftruncate设置的MEMORY_SIZE必须等于shared_memory_t的完整大小(或至少包含shared_parking_t data的全部内容),否则会出现内存越界或数据截断,导致跨进程访问异常。


修改后的Parent创建共享内存代码

bool create_shared_object(shared_memory_t* shm) {
    const char* share_name = shared_memory_name;
    // 注意:shm_unlink需确保无其他进程使用该共享内存时执行
    shm_unlink(share_name);
    shm->name = share_name;

    shm->fd = shm_open(shm->name, O_CREAT | O_EXCL | O_RDWR, S_IRWXU | S_IRWXG | S_IRWXO);    
    if(shm->fd == -1){
        fprintf(stderr, "shm_open(%s): %s (%d)\n", shm->name, strerror(errno), errno);
        return false;
    }

    // 确保共享内存大小与结构体一致
    if (ftruncate(shm->fd, sizeof(shared_memory_t))){
        fprintf(stderr, "ftruncate(%s): %s (%d)\n", shm->name, strerror(errno), errno);
        close(shm->fd);
        shm_unlink(share_name);
        return false;
    }

    // 将共享内存映射到外部传入的shm结构体地址
    void* mapped_addr = mmap(shm, sizeof(shared_memory_t),
        PROT_WRITE | PROT_READ, MAP_SHARED | MAP_FIXED, shm->fd, 0);
    if (mapped_addr == MAP_FAILED){
        fprintf(stderr, "mmap(%s, %zu): %s (%d)\n", shm->name, sizeof(shared_memory_t), strerror(errno), errno);
        close(shm->fd);
        shm_unlink(share_name);
        return false;     
    }   
    return true;
}

修改后的Child打开共享内存代码

bool create_shared_object(shared_memory_t* shm) {
    const char* share_name = shared_memory_name;
    shm->name = share_name;

    shm->fd = shm_open(shm->name, O_RDWR, 0);
    if(shm->fd == -1){
        fprintf(stderr, "shm_open(%s): %s (%d)\n", shm->name, strerror(errno), errno);
        return false;
    }

    // 将共享内存映射到外部传入的shm结构体地址
    void* mapped_addr = mmap(shm, sizeof(shared_memory_t),
        PROT_WRITE | PROT_READ, MAP_SHARED | MAP_FIXED, shm->fd, 0);
    if (mapped_addr == MAP_FAILED){
        fprintf(stderr, "mmap(%s, %zu): %s (%d)\n", shm->name, sizeof(shared_memory_t), strerror(errno), errno);
        close(shm->fd);
        return false;
    }

    return true;
}

额外注意事项

  1. 使用MAP_FIXED时需确保shm指向的内存区域未被占用,避免覆盖其他数据;若不想用MAP_FIXED,可调整结构体设计,添加指针字段指向映射的共享内存区域。
  2. 共享内存中的条件变量和互斥锁必须设置进程共享属性(通过pthread_mutexattr_setpshared和pthread_condattr_setpshared配置),否则跨进程无法正常同步。
  3. 进程退出时需调用munmap解除映射、close关闭文件描述符;parent进程在不再需要共享内存时执行shm_unlink清理资源。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.18 02:55:20