共享内存本身不带同步能力,必须配信号量等同步原语才能安全读写;POSIX下常用shm_open+mmap+sem_open组合,Windows则用CreateFileMapping+CreateSemaphore实现等效逻辑。

共享内存本身不带同步能力,必须配信号量(或其他同步原语)才能安全读写——这是最常被忽略的前提。
POSIX 信号量 + shm_open 是跨平台首选
Linux/macOS 上用 shm_open + mmap 创建共享内存段,再用 sem_open 创建命名信号量,两者通过名字关联。Windows 不支持 POSIX 共享内存,但可改用 CreateFileMapping + CreateSemaphore 实现等效逻辑。
关键点:
-
sem_open必须传O_CREAT标志且指定权限(如0644),否则其他进程无法打开 - 信号量初始值要设对:生产者-消费者模型中,空缓冲区对应信号量初值为 0(无数据可读),满缓冲区对应初值为 0(无空间可写)
-
sem_wait和sem_post必须成对出现在临界区前后,且不能在munmap或shm_unlink后继续调用——此时信号量句柄可能已失效
System V 信号量(semget)容易踩的坑
老式接口兼容性好,但 key 冲突和生命周期管理更难控。常见错误现象:semget 返回 -1 且 errno == EINVAL,大概率是 key_t 值没对齐或 ftok 输入路径不存在。
立即学习“C++免费学习笔记(深入)”;
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
使用时注意:
- 不要复用
ftok("/tmp", 'a')这类硬编码路径——路径必须真实存在且所有进程有读权限 -
semctl(..., SETVAL)只能由第一个创建信号量的进程调用;后续进程打开后不能重置值 - 忘记调用
semctl(..., IPC_RMID)会导致信号量残留,ipcs -s可查,ipcrm -s <semid>手动清理
Windows 下 CreateSemaphore + CreateFileMapping 的典型配对
Windows 没有 POSIX 共享内存,必须用文件映射对象模拟。信号量名和共享内存名必须全局唯一,且建议加前缀避免冲突(如 L"MyApp_Shm" 和 L"MyApp_Sem")。
关键参数不能错:
-
CreateFileMapping的hFile必须为INVALID_HANDLE_VALUE,否则会尝试映射真实文件 -
flProtect设为PAGE_READWRITE,若设PAGE_READONLY则写操作触发访问违例 -
CreateSemaphore的初始计数(lInitialCount)和最大计数(lMaximumCount)必须一致,否则ReleaseSemaphore可能失败
同步粒度决定性能和复杂度
一个信号量保护整块共享内存最简单,但会成为瓶颈;拆成多个信号量(如“空位数”“已填数”两个)能提升并发,但逻辑变重。无锁方案(如原子 head/tail 环形缓冲区)适合 GB 级高频传输,但要求双方对缓存一致性、内存序(memory_order_acquire/release)、结构体对齐完全可控——稍有偏差就会静默出错。
最容易被忽略的是:信号量只是同步手段,不是数据校验机制。即使加了锁,若写入方未写满结构体、接收方未检查长度字段,仍会读到脏数据。

















