共享内存(Shared Memory)是IPC 进程间通信方式之一,原理:在内核开辟一块物理内存,多个进程将这块内存映射到自己的虚拟地址空间,直接读写内存,无需内核拷贝数据,速度最快;但没有自带同步互斥,一般要搭配信号量、互斥锁使用。
完整函数链路:
ftok()→shmget()→shmat()→ 读写内存 →shmdt()→shmctl()
1. ftok —— 生成 IPC 键值 key_t
#include <sys/types.h> #include <sys/ipc.h>key_t ftok(const char *pathname, int proj_id);参数说明
pathname:存在的文件路径(必须真实存在,一般用当前目录.)proj_id:项目 ID,0~255 之间的整数(常用字母,如'a')
返回值
- 成功:返回
key_t类型键值(用于 shmget、msgget、semget) - 失败:
-1,设置 errno
原理
ftok 根据 文件设备号、文件 inode、proj_id 组合算出唯一 key; ⚠️ 注意:文件删除重建后,inode 变化,ftok 结果会变。
注意:用ipcs查看
2. shmget —— 创建 / 获取共享内存段(建立key和stimid的关系)
#include <sys/ipc.h> #include <sys/shm.h>int shmget(key_t key, size_t size, int shmflg);参数
key:ftok 得到的键值;特殊值IPC_PRIVATE代表私有共享内存(只用于亲缘进程)size:共享内存大小,建议 4k 对齐(内存页大小)shmflg:权限 + 创建标志IPC_CREAT:不存在则创建,存在直接获取IPC_EXCL:搭配 IPC_CREAT,存在则报错- 权限位:
0666类似文件权限
一般就是IPC_CREAT|0666
返回值
- 成功:shmid 共享内存标识符(int),后续操作都用它
- 失败:
-1
3. shmat —— 挂载(映射)共享内存到进程虚拟地址(建立映射--获得地址)
attach:把内核共享内存映射到当前进程地址空间,得到可用指针。
void *shmat(int shmid, const void *shmaddr, int shmflg);参数
shmid:要映射的本地内存shmaddr:本地可用地址 一般不确定--》NULLshmflg:挂载属性0:可读可写SHM_RDONLY:只读挂载
返回值
- 成功:返回映射后的起始虚拟地址指针(void*,强制转换使用)
- 失败:
(void *)-1
4. shmdt —— 脱离共享内存(解除映射)
detach:进程用完共享内存,断开映射;不会删除内核中的共享内存段!
int shmdt(const void *shmaddr);参数
shmaddr:shmat 返回的映射起始地址
返回值
成功返回 0;失败 -1
eg:if(shmdt(p)<0)
5. shmctl —— 共享内存控制(获取信息、删除、设置属性)
control,多功能控制函数,最常用:IPC_RMID 删除共享内存
int shmctl(int shmid, int cmd, struct shmid_ds *buf);参数
shmid:共享内存 idcmd:控制命令(重点三个)IPC_RMID:标记删除共享内存,只有所有进程都 shmdt 脱离后,内核才真正释放,此时 buf 传 NULLIPC_STAT:获取共享内存属性,存入 bufIPC_SET:修改共享内存权限等属性
一般就用IPC_RMID
3、buf:shmid_ds 结构体指针,IPC_RMID 填 NULL
返回值
成功 0,失败 - 1
eg:if(shmctl(shmid,IPC_RMID,NULL)<0)
总结:
共享内存
a.key -- ftok
b.shmid -- shmget
c.映射 -- shmat
d.解除 -- shmdt
e.销毁 -- shmctl