c++如何操作共享内存IPC_c++ shmget与shmat在Linux下的使用【方法】
技术百科
裘德小鎮的故事
发布时间:2025-12-31
浏览: 次 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
}解决方法:- 用
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),读写前后semopP/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) ...
// 写后解锁
op.sem_op = 1;
semop(semid, &op, 1);
共享内存不是“开箱即用”的安全通信方式,页对齐、显式销毁、外置同步这三点漏掉任何一项,上线后都容易变成偶发性崩溃或数据错乱。尤其在多进程长期运行的服务中,残留段和未释放信号量会越积越多。
# ai
# 的是
# 放在
# 都是
# 是因为
# 还在
# 多个
# 解决方法
# 还能
# linux
# 并发
# c++
# if
# void
# 编码
# 字节
# 指针
# 同步机制
# red
# NULL
# 时用
# 封装
# 结构体
# while
# Struct
# char
# len
# errno
# 信号量
# 已满
相关栏目:
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
AI推广<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
SEO优化<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
技术百科<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
谷歌推广<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
百度推广<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
网络营销<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
案例网站<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
精选文章<?muma echo $count; ?>
】
相关推荐
- Win11怎么更改系统语言为中文_Windows1
- Win11如何设置系统声音_Win11系统声音调整
- Win10如何卸载预装Edge扩展_Win10卸载
- Win11开机速度慢怎么优化_Win11系统启动加
- Linux怎么设置磁盘配额_Linux系统Quot
- Python深度学习实战教程_神经网络模型构建与训
- Go 语言标准库为何不提供泛型 Contains
- Mac的“预览”如何合并多个PDF_Mac文件处理
- Mac怎么安装软件_Mac安装dmg与pkg文件的
- Win11开机自检怎么关闭_跳过Win11开机磁盘
- VSC里PHP变量未定义报错怎么解决_错误抑制技巧
- Windows10无法连接到Internet_Wi
- Mac怎么设置登录项_Mac管理开机自启动程序【教
- Win11怎么关闭右下角弹窗_Win11拦截系统通
- PythonPandas数据分析教程_数据清洗与处
- Python数据挖掘核心算法实践_聚类分类与特征工
- C#如何在一个XML文件中查找并替换文本内容
- C++如何解析JSON数据?(nlohmann/j
- Win11如何添加/删除输入法 Win11切换中英
- windows系统找不到无线网络怎么办_windo
- Mac如何将HEIC图片格式转为JPG_Mac批量
- 如何在同包不同文件中正确引用 Go 结构体
- 如何高效获取循环末次生成的 NumPy 数组最后一
- 短链接怎么用php递归还原_多层加密链接的处理法【
- 如何在Golang中使用time处理时间_Gola
- Win11时间格式怎么改成12小时制 Win11时
- c++怎么实现大文件的分块读写_c++ 文件指针s
- Win11怎么设置桌面图标间距_Windows11
- Win10怎么卸载爱奇艺_Win10彻底卸载爱奇艺
- Win11怎样安装剪映专业版_Win11安装剪映教
- MAC的“接续互通”功能无法使用怎么办_MAC检查
- Win11怎样安装网易云音乐_Win11安装网易云
- php8.4如何调用com组件_php8.4win
- Windows服务持续崩溃怎样修复_系统服务保护机
- Windows 10怎么把任务栏放在屏幕上方_Wi
- Win11怎么清理C盘系统日志_Win11清理系统
- LINUX如何查看文件类型_Linux中file命
- Python正则表达式实战_模式匹配说明【教程】
- c# 如何深拷贝和浅拷贝
- c# Task.ConfigureAwait(tr
- Win11怎么关闭专注助手 Win11关闭免打扰模
- Go语言中正确反序列化多个同级XML元素为结构体切
- Win11怎么设置屏保_Windows 11屏幕保
- Python邮件系统自动化教程_批量发送解析与模板
- MAC如何安装Git版本控制工具_MAC开发环境配
- Windows10如何更改桌面图标间距_Win10
- Mac怎么开启“任何来源”_Mac安装未签名应用的
- Windows电脑如何截屏?(四种快捷方法)
- Python高性能计算项目教程_NumPyCyth
- 如何使用Golang优化模块引入路径_Golang

QQ客服