合成键
#include <sys/ipc.h>
key_t ftok(const char* pathname, int proj_id);
功能:用于合成一个键
参数:pathname 一个真实存在的路径名
proj_id 项目ID,仅低8位有效,取0到255之间的数
返回值:创建或获取IPC对象的键,失败返回-1ftok函数用pathname参数调用stat函数,将其输出的stat结构体中的st_dev(设备ID)和st_ino(i节点号)成员与proj_id参数组合来生成键
参与生成键的是设备ID和节点号,而不是pathname参数字符串本身
设备ID和i节点号都至少是整型字长的数据,而键也是整型字长,再加上一个字节项目ID,在合成键的过程中难免会丢失一部分信息。因此有时候明明提供的是不同的路径,该函数返回的键却是一样的
共享内存
#include <sys/shm.h>
int shmget(key_t key, size_t size, int shmflg);
功能:创建新的或获取已有的共享内存
参数:key 键
size 字节数,自动按页取整
shmflg:创建标志
0 获取,不存在即失败
IPC_CREAT 创建,不存在即创建,已存在即获取
IPC_EXCL 排它,不存在即创建,已存在即失败
返回值:成功返回共享内存的ID,失败返回-1#include <sys/shm.h>
void* shmat(int shmid, void const* shmaddr, int shmflg);
功能:加载共享内存,将物理内存中的共享区域映射到进程用户空间的虚拟内存中
参数:shmid 共享内存的ID
shmaddr 映射到共享内存的虚拟内存起始地址,取NULL由系统自动选择
shmflg:加载标志
0 以读写方式使用共享
SHM_RDONLY 以只读方式使用共享内存
返回值:成功返回共享内存的起始地址,失败返回(void*)-1
shmat函数每建立一个映射,系统内核中共享内存对象的加载计数加1
#include <sys/shm.h>
int shmdt(void const* shmaddr);
功能:卸载共享内存
参数:shmaddr 共享内存的起始地址
返回值:成功返回0,失败返回-1
shmdt函数卸载后系统内核中共享内存对象的加载计数减1#include <sys/shm.h>
int shmctl(int shmid, IPC_RMID, NULL);
功能:销毁共享内存
参数:shmid 共享内存对象ID
返回值:成功返回0,失败返回-1
销毁共享内存。内核会做一个销毁标记,禁止形成新的加载,但保留已有加载。只有当其使用者们纷纷卸载,加载计数降为0时,共享内存才会真的被销毁| 步骤 | 进程A | 函数 | 进程B | 步骤 |
|---|---|---|---|---|
| 1 | 创建共享内存 | shmget | 获取共享内存 | 1 |
| 2 | 加载共享内存 | shmat | 加载共享内存 | 2 |
| 3 | 使用共享内存 | strcpy / printf / ... | 使用共享内存 | 3 |
| 4 | 卸载共享内存 | shmdt | 卸载共享内存 | 4 |
| 5 | 销毁共享内存 | shmctl | — | — |
共享内存的地址空间通常被映射到堆和栈之间,速度快但缺乏足够的同步机制
消息队列
#include <sys/msg.h>
int msgget(key_t key, int msgflg);
功能:创建新的或获取已有的消息队列
参数:key 键
msgflg:创建标志
0 获取,不存在即失败
IPC_CREAT 创建,不存在即创建,已存在即获取
IPC_EXCL 排它,不存在即创建,已存在即失败
返回值:成功返回消息队列的ID,失败返回-1#include <sys/msg.h>
int msgsnd(int msgid, void const* msgp, size_t msgsz, int msgflg);
功能:发送消息
参数:msgid 消息队列的ID。
msgp: 指向一个包含消息类型和消息数据的结构体。该内存块的前4个字节必须是一个大于0的整数,代表消息类型,其后紧跟消息数据
msgsz: 期望发送消息数据(不含消息类型)的字节数
msgflg: 发送标志,一般取0即可
IPC_NOWAIT 当消息达到上限时msgsnd不会阻塞等待,而是返回-1,同时errno为EAGAIN
返回值:成功返回0,失败返回-1#include <sys/msg.h>
int msgrcv(int msgid, void* msgp, size_t msgsz, long msgtyp, int msgflg);
功能:接收消息
参数:msgid 消息队列的ID
msgp:指向一个结构体包含消息类型(4字节)和消息数据的内存
msgsz:期望接收消息数据(不含消息类型)的字节数
msgflg:接收标志,一般取0即可
msgtyp:消息类型
0 提取消息队列的第一条消息
>0 当 msgflg 参数不包含 MSG_EXCEPT 位,则提取消息队列的第一条类型为 msgtyp 的消息;若包含,则提取消息队列的第一条类型不为 msgtyp 的消息
<0 提取消息队列中类型小于等于 msgtyp 绝对值的消息,类型越小的优先级越高
msgflg:接收标志,一般取 0 即可
IPC_NOWAIT 没有可接收消息时msgrcv不会阻塞等待,而是返回-1(errno=ENOMSG)
MSG_EXCEPT 跳过消息类型
MSG_NOERROR 默认接收消息数据大于msgsz,函数失败返回-1(errno=E2BIG),包含后舍弃大于msgsz的字节数
返回值:成功返回实际接收到的消息数据字节数,失败返回 -1#include <sys/msg.h>
int msgctl(int msgid, IPC_RMID, NULL);
功能:销毁消息队列
参数:msgid 消息队列的ID
返回值:成功返回0,失败返回-1| 步骤 | 进程A | 函数 | 进程B | 步骤 |
|---|---|---|---|---|
| 1 | 创建消息队列 | msgget | 获取消息队列 | 1 |
| 2 | 发送接收消息 | msgsnd / msgrcv | 发送接收消息 | 2 |
| 3 | 销毁消息队列 | msgctl | — | — |
可发送消息字节数上限:8192
单条队列消息总字节数上限:16384 (16K)
全系统总消息队列数上限:16
全系统消息总字节数上限:262144 (256K = 16 x 16K)
查看系统中的IPC对象
ipcs -m (memory, 共享内存)
ipcs -q (message queue, 消息队列)
ipcs -s (semphore, 信号量集)
ipcs -a (all, 所有的)
删除系统中的IPC对象
ipcrm -m 删除共享内存
ipcrm -q 删除消息队列
ipcrm -s 删除信号量集