0

0

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

裘德小鎮的故事

裘德小鎮的故事

发布时间:2025-12-31 17:57:40

|

110人浏览过

|

来源于php中文网

原创

shmget 返回 -1 且 errno=EINVAL 通常因 key 无效、size 未页面对齐或系统限制已满;需用 getpagesize() 对齐 size,ftok() 生成合法 key,并用 ipcs/ipcrm 检查调整系统参数。

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

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
}
解决方法

  • getpagesize() 获取页大小,向上对齐:size = ((size + getpagesize() - 1) / getpagesize()) * getpagesize();
  • 确认 key 是合法的 —— 推荐用 ftok("/tmp", 'a') 生成,避免硬编码非法值(如 0 或负数)
  • 检查系统限制:ipcs -l 查看最大段数、单段最大字节等;必要时用 sysctl -w kernel.shmall=2097152 调整(需 root)

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

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

  • 不要依赖 sizeof(*ptr) 判断共享区大小
  • 建议封装结构体头 + 数据体,头里存实际有效长度(如 struct shm_header { size_t len; char data[]; }
  • 使用前强制校验:if (ptr == (void*)-1) { /* 错误 */ },但注意:成功返回也可能为 NULL(若用了 SHM_REMAP 且地址冲突)

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

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

  • 只调 shmdt 就以为清理完了 → 实际段仍存在,ipcs -m 还能看见,且 shmget 会复用旧段
  • 在子进程里调 IPC_RMID → 父进程再访问会出错(shmat 失败或读到垃圾)
  • 没做异常路径清理 → crash 或 early return 导致漏掉 shmctl
稳妥做法:
  • 由创建者(通常是父进程或主控进程)统一负责 IPC_RMID
  • atexit() 或 RAII(如自定义 shm_segment 类)确保释放
  • 调试时用 ipcs -m + ipcrm -M 手动清理残留

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

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

  • semget/semop 配套信号量(推荐):初始化时 semget(key, 1, IPC_CREAT|0666),读写前后 semop P/V
  • 慎用 pthread_mutex_t:需放在共享内存内且用 PTHREAD_PROCESS_SHARED 属性初始化,否则只对本进程有效
  • 避免轮询等待:不要用 while(!flag) sleep(1),改用信号量或 sem_wait
  • 注意初始化顺序:信号量必须在共享内存就绪后初始化,否则其他进程 semop 会失败
一个最小可行同步示例:
// 初始化信号量(仅一次)
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) ...

稿定AI绘图
稿定AI绘图

稿定推出的AI绘画工具

下载

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

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

立即学习C++免费学习笔记(深入)”;

相关专题

更多
c语言中null和NULL的区别
c语言中null和NULL的区别

c语言中null和NULL的区别是:null是C语言中的一个宏定义,通常用来表示一个空指针,可以用于初始化指针变量,或者在条件语句中判断指针是否为空;NULL是C语言中的一个预定义常量,通常用来表示一个空值,用于表示一个空的指针、空的指针数组或者空的结构体指针。

229

2023.09.22

java中null的用法
java中null的用法

在Java中,null表示一个引用类型的变量不指向任何对象。可以将null赋值给任何引用类型的变量,包括类、接口、数组、字符串等。想了解更多null的相关内容,可以阅读本专题下面的文章。

434

2024.03.01

if什么意思
if什么意思

if的意思是“如果”的条件。它是一个用于引导条件语句的关键词,用于根据特定条件的真假情况来执行不同的代码块。本专题提供if什么意思的相关文章,供大家免费阅读。

712

2023.08.22

while的用法
while的用法

while的用法是“while 条件: 代码块”,条件是一个表达式,当条件为真时,执行代码块,然后再次判断条件是否为真,如果为真则继续执行代码块,直到条件为假为止。本专题为大家提供while相关的文章、下载、课程内容,供大家免费下载体验。

81

2023.09.25

golang结构体相关大全
golang结构体相关大全

本专题整合了golang结构体相关大全,想了解更多内容,请阅读专题下面的文章。

193

2025.06.09

golang结构体方法
golang结构体方法

本专题整合了golang结构体相关内容,请阅读专题下面的文章了解更多。

185

2025.07.04

javascriptvoid(o)怎么解决
javascriptvoid(o)怎么解决

javascriptvoid(o)的解决办法:1、检查语法错误;2、确保正确的执行环境;3、检查其他代码的冲突;4、使用事件委托;5、使用其他绑定方式;6、检查外部资源等等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

173

2023.11.23

java中void的含义
java中void的含义

本专题整合了Java中void的相关内容,阅读专题下面的文章了解更多详细内容。

92

2025.11.27

php源码安装教程大全
php源码安装教程大全

本专题整合了php源码安装教程,阅读专题下面的文章了解更多详细内容。

3

2025.12.31

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
PostgreSQL 教程
PostgreSQL 教程

共48课时 | 6.3万人学习

Git 教程
Git 教程

共21课时 | 2.3万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号