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

Linux Ubuntu共享内存shmat映射失败问题排查

共享内存shmat调用失败排查问题

问题描述

在Linux Ubuntu系统中实现基于共享内存的进程间通信(IPC),逻辑为:先尝试获取已存在的共享内存,若不存在则创建,调整至目标大小后映射使用。但每次运行时shmat调用均失败,报错“Fatal error mapping shared memory”,相关代码及运行错误信息如下:

错误代码

#include <iostream>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/sem.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <cstring>

#define SHARED_MEMORY_KEY "/mysharedmemory"

typedef struct
{
    int code;
    char buffer[500];
} shared_data_t;

shared_data_t *shared_mem_ptr;

void init_shared_memory()
{
    // Open shared memory
    int shmid = shm_open(SHARED_MEMORY_KEY, O_CREAT | O_RDWR, 0644);

    std::cout << "OPEN: " << shmid << std::endl;

    if (shmid < 0)
    {
        std::cout  << "Not found... creating..." << std::endl;

        key_t key = ftok(SHARED_MEMORY_KEY, 1);

        // Does not exist - create it
        shmid = shmget(key, sizeof(shared_data_t), 0644 | IPC_CREAT);

        if (shmid == -1)
        {
            std::cout << "Fatal error creating shared memory." << std::endl;
            return;
        }
    }

    int rc = ftruncate(shmid, sizeof(shared_data_t));

    if (rc == -1)
    {
        std::cout << "Fatal error resizing shared memory." << std::endl;
        return;
    }

    // Attach data struct to the segment to get a pointer to it.
    shared_mem_ptr = (shared_data_t *) shmat(shmid, NULL, 0);

    if (shared_mem_ptr == (void *)-1)
    {
        std::cout << "Fatal error mapping shared memory." << std::endl;
        return;
    }
}

运行错误信息

Fatal error mapping shared memory

错误原因分析

代码混用了两种完全不兼容的共享内存API:

  • shm_open属于POSIX共享内存接口,返回的是文件描述符,后续需用mmap映射内存,而非shmat
  • shmget/shmat属于System V共享内存接口,依赖key_t标识,和POSIX接口完全不互通

当shm_open成功获取文件描述符后,直接传给shmat必然失败——shmat需要的是System V共享内存ID(shmget返回值),而非POSIX共享内存的文件描述符。此外,ftok要求传入已存在的文件路径,若/mysharedmemory不存在,ftok会返回错误,导致后续shmget也失败。


修正方案

选择其中一种API实现即可,以下提供两种修正版本:

方案1:使用POSIX共享内存(推荐)

#include <iostream>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <cstring>
#include <unistd.h>
#include <errno.h>

#define SHARED_MEMORY_KEY "/mysharedmemory"

typedef struct
{
    int code;
    char buffer[500];
} shared_data_t;

shared_data_t *shared_mem_ptr;

void init_shared_memory()
{
    // 打开或创建POSIX共享内存
    int fd = shm_open(SHARED_MEMORY_KEY, O_CREAT | O_RDWR, 0644);
    if (fd < 0)
    {
        perror("shm_open failed");
        return;
    }

    // 调整共享内存大小
    if (ftruncate(fd, sizeof(shared_data_t)) == -1)
    {
        perror("ftruncate failed");
        close(fd);
        return;
    }

    // 映射共享内存到进程地址空间
    shared_mem_ptr = (shared_data_t*)mmap(NULL, sizeof(shared_data_t), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
    if (shared_mem_ptr == MAP_FAILED)
    {
        perror("mmap failed");
        close(fd);
        return;
    }

    // 映射完成后可关闭文件描述符(内存依然有效)
    close(fd);
}

方案2:使用System V共享内存

#include <iostream>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <cstring>
#include <unistd.h>
#include <errno.h>

#define SHARED_MEMORY_FILE "/tmp/mysharedmemory"
#define PROJECT_ID 1

typedef struct
{
    int code;
    char buffer[500];
} shared_data_t;

shared_data_t *shared_mem_ptr;

void init_shared_memory()
{
    // 确保文件存在,用于生成key
    int fd = open(SHARED_MEMORY_FILE, O_CREAT | O_RDWR, 0644);
    if (fd < 0)
    {
        perror("open failed");
        return;
    }
    close(fd);

    // 生成System V共享内存的key
    key_t key = ftok(SHARED_MEMORY_FILE, PROJECT_ID);
    if (key == -1)
    {
        perror("ftok failed");
        return;
    }

    // 获取或创建System V共享内存
    int shmid = shmget(key, sizeof(shared_data_t), 0644 | IPC_CREAT);
    if (shmid == -1)
    {
        perror("shmget failed");
        return;
    }

    // 映射共享内存到进程地址空间
    shared_mem_ptr = (shared_data_t*)shmat(shmid, NULL, 0);
    if (shared_mem_ptr == (void*)-1)
    {
        perror("shmat failed");
        return;
    }
}

额外提示

  • POSIX共享内存接口更现代,用文件系统路径标识,管理更直观,推荐使用
  • 调试时用perror打印具体错误原因,比自定义信息更利于排查问题
  • 使用完共享内存后,POSIX接口需调用munmap解除映射、shm_unlink删除共享内存;System V接口需调用shmdt解除映射、shmctl删除共享内存

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 23:32:05