一、什么是共享内存共享内存是最快的 IPC 形式。一旦共享内存映射到进程的地址空间数据传递不再涉及内核进程无需通过系统调用即可直接读写内存。特点最快无内核介入直接访问需要同步必须配合信号量使用否则会有数据竞争内核持久共享内存不会随进程退出而自动销毁必须手动删除。需要显式删除命令行使用 ipcrm代码中使用 shmctl IPC_RMID。注System V 接口较复杂新项目推荐使用 POSIX 共享内存。二、共享内存示意图管道、消息队列数据都需要经过内核拷贝。共享内存是最快的 IPC 方式因为它不经过内核。进程 A 有一个虚拟地址比如 0x7f…通过它的页表指向了物理内存中的某个位置。进程 B 也有一个虚拟地址通过它的页表指向了同一块物理内存。进程 A 和进程 B 读写的是同一块物理内存整个过程没有经过内核拷贝。A 写完后B 直接就能看到不需要调用 read 或 write 系统调用。三、共享内存数据结构structshmid_ds{structipc_permshm_perm;intshm_segsz;__kernel_time_t shm_atime;__kernel_time_t shm_dtime;__kernel_time_t shm_ctime;__kernel_ipc_pid_t shm_cpid;__kernel_ipc_pid_t shm_lpid;unsignedshortshm_nattch;unsignedshortshm_unused;void*shm_unused2;void*shm_unused3;};核心要点权限由 shm_perm 控制大小 shm_segsz 创建后固定shm_nattch 为0时才能安全删除共享内存时间戳和PID字段记录操作历史四、共享内存函数shmget#includesys/ipc.h#includesys/shm.hintshmget(key_tkey,size_tsize,intshmflg);参数key 共享内存键值 ftok() 生成 或 IPC_PRIVATE size 共享内存大小字节shmflg IPC_CREAT (创建)、 IPC_EXCL (确保新建)、权限位(如 0644 )返回值成功返回 shmid 失败返回 -1示例intshmidshmget(IPC_PRIVATE,4096,IPC_CREAT|0644);shmat#includesys/types.h#includesys/shm.hvoid*shmat(intshmid,constvoid*shmaddr,intshmflg);参数shmid shmget 返回的标识符shmaddr NULL (系统自动选地址) 或 指定地址shmflg SHM_RDONLY (只读)、 SHM_RND (地址对齐)返回值成功返回共享内存首地址指针失败返回 (void *)-1连接地址规则1.shmaddr 为 NULL系统自动选择连接地址2.shmaddr 非 NULL 且无 SHM_RND使用指定地址3.shmaddr 非 NULL 且有 SHM_RND地址自动向下对齐到 SHMLBA 的整数倍示例char*addr(char*)shmat(shmid,NULL,0);shmdt#includesys/types.h#includesys/shm.hintshmdt(constvoid*shmaddr);参数 shmat 返回的地址指针返回值成功返回 0 失败返回 -1注意分离≠删除进程终止会自动分离shmctl#includesys/ipc.h#includesys/shm.hintshmctl(intshmid,intcmd,structshmid_ds*buf);参数shmid 共享内存标识符cmd IPC_STAT (获取状态)、 IPC_SET (设置属性)、 IPC_RMID (标记删除)buf shmid_ds 结构体指针返回值成功返回 0 失败返回 -1示例shmctl(shmid,IPC_RMID,NULL);// 删除共享内存五、共享内存与信号量配合使用为什么需要信号量共享内存本身不提供任何同步机制如果多个进程同时读写同一块共享内存会导致数据竞争。例如进程 A 正在写入共享内存但只写了一半进程 B 同时读取就会读到不完整的数据。解决方案是使用信号量实现互斥访问保证同一时刻只有一个进程读写共享内存。信号量类型选择与 System V 共享内存配合使用时推荐使用 POSIX 命名信号量。命名信号量通过 sem_open 创建和打开使用 sem_close 关闭sem_unlink 删除适用于无亲缘关系的进程间同步。无名信号量则通过 sem_init 初始化sem_destroy 销毁主要用于线程间或有亲缘关系的进程。核心操作创建或打开信号量使用 sem_open加锁使用 sem_waitP 操作解锁使用 sem_postV 操作关闭信号量使用 sem_close最后用 sem_unlink 删除信号量。使用流程注意事项信号量初始值必须设为 1 才能实现互斥锁的效果。P 操作必须在访问共享内存之前调用V 操作必须在访问共享内存之后调用并且要确保解锁操作会被执行以防止死锁。最后一个使用共享内存和信号量的进程负责删除它们。编译时需要链接 -lrt 和 -lpthread 库。注意以下常见错误忘记加锁会导致数据竞争读到不完整的数据忘记解锁会导致死锁其他进程永远等待信号量未初始化会导致未定义行为未处理异常退出会导致信号量未被释放造成死锁。