贝利信息

c++如何操作共享内存IPC_c++ shmget与shmat在Linux下的使用【方法】

日期:2025-12-31 00:00 / 作者:裘德小鎮的故事
shmget 返回 -1 且 errno=EINVAL 通常因 key 无效、size 未页面对齐或系统限制已满;需用 getpagesize() 对齐 size,ftok() 生成合法 key,并用 ipcs/ipcrm 检查调整系统参数。

shmget 返回 -1 且 errno=EINVAL 怎么办

这通常是因为 key 无效、size 不对齐,或系统限制已满。Linux 共享内存段大小必须是页面对齐的(通常是 4096 字节),传入非对齐值(比如 1000)会导致 shmget 失败。
检查方式:

int size = 1000;
int shmid = shmget(key, size, IPC_CREAT | 0666);
if (shmid == -1) {
    perror("shmget");
    // 输出类似:Invalid argument
}
解决方法:

shmat 后指针操作越界却没报错?

shmat 返回的是 void*,它只是把共享内存映射到当前进程地址空间,并不提供边界检查。写超 shmget 指定的 size,可能覆盖相邻内存、触发段错误,也可能静默破坏其他变量 —— 行为完全未定义。
务必自己维护长度信息:

进程退出后共享内存还在,怎么清理

共享内存段生命周期独立于创建它的进程。shmdt 只解除映射,shmctl(shmid, IPC_RMID, nullptr) 才真正标记删除 —— 但要等所有进程都 shmdt 后才真正释放。
常见误操作:

稳妥做法:

多个进程如何安全读写同一块共享内存

共享内存本身不带同步机制。直接并发读写必然导致数据竞争,struct 成员被部分更新、计数器错乱、指针悬空都是常态。
必须配合其他 IPC 原语:

一个最小可行同步示例:
// 初始化信号量(仅一次)
int semid = semget(ftok("/tmp", 's'), 1, IPC_CREAT|0666);
semctl(semid, 0, SETVAL, 1); // 初始值为 1

// 写前加锁 struct sembuf op = {0, -1, SEM_UNDO}; semop(semid, &op, 1);

// ... memcpy(shm_ptr, data, size) ...

// 写后解锁 op.sem_op = 1; semop(semid, &op, 1);

共享内存不是“开箱即用”的安全通信方式,页对齐、显式销毁、外置同步这三点漏掉任何一项,上线后都容易变成偶发性崩溃或数据错乱。尤其在多进程长期运行的服务中,残留段和未释放信号量会越积越多。