AT - 创建,不存在则创建 存在则获取(除非指定IPC_EXCL)
如果IPC_CREAT需要给定共享内存的权限(mode) IPC_CREAT|0644
IPC_EXCL - 排斥,和IPC_CREAT按位域,如果共享内存已经存在则失败
成功返回共享内存的标识,失败返回-1
*/
//2.加载共享内存 将进程中的虚拟内存地址映射到共享内存中
void* shmat(int shmid,void *shmaddr,int shmflg);
/*
A.将shmid(shmget的返回值)参数所标识的共享内存,映射到调用进程的地址空间
B.可以通过参数shmaddr(进程中的虚拟地址)人为指定映射地址,也可以将参数置为NULL,由系统自动选择
C.参数shmflg标识:
0 - 以读写方式使用共享内存
SHM_RDONLY - 以只读方式使用共享内存
SHM_RND - 只在shmaddr参数非NULL时才起作用,表示对shmaddr参数向下取内存页的整数倍作为映射地址
成功返回映射地址,失败返回-1(0XFFFFFFF)
如果加载成功,内核将该共享内存的加载计数加1(共享内存由内核维护,记录有多少个进程加载了该共享内存)
*/
//3.卸载共享内存
int shmdt(const void *shmaddr);
/*
将参数shmaddr所指向加载的共享内存映射从调用进程的取消映射
成功返回0,失败返回-1
如果卸载成功,内核会将该共享内存的加载计数减1
*/
//4.销毁/控制共享内存
int shmctl(int shmid,int cmd,struct shmid_ds* buf);
/*
A.参数shmid是shmget的返回值 是对shmid所标识的共享内存进行删除/获取共享内存的信息
B.cmd取值
IPC_STAT - 获取共享内存的属性,通过buf参数输出
IPC_SET - 设置共享内存的属性,通过buf参数输入,仅三个属性可设置
shm_perm.uid 用户ID
shm_perm.gid 组ID
shm_perm.mode 权限
IPC_RMID - 标记删除共享内存
并非真正删除共享内存,只是做一个删除标记,禁止其被继续加载,但已有加载依然保留。
只有当该共享内存的加载计数为0且使用IPC_RMID时才真正被删除
成功返回0 失败返回-1
*/
struct shmid_ds{
struct ipc_perm shm_perm; //所有者及权限
size_t shm_segsz; //共享内存大小(以字节为单位)
time_t shm_atime; //最后加载时间
time_t shm_dtime; //最后卸载时间
time_t shm_ctime; //最后修改时间
pid_t shm_cpid; //创建共享内存的进程ID
pid_t shm_lpid; //最后加载、卸载进程的ID
shmatt_t shm_nattch; //当前加载计数
...
};
struct ipc_perm{
key_t __key; //键值
uid_t uid; //有效属主ID
gid_t gid; //有效属组ID
uid_t cuid; //有效创建者ID
gid_t cgid; //有效创建组ID
unsigned short mode; //权限
unsigned short __seq;//序列号
};
#ipcs -m #查看当前系统的共享内存
#ipcrm -m shmid #删除指定的共享内存
消息队列 基本特点
- 消息队列是由一个系统内核负责存储和管理,并通过消息队列标识引用的数据链表
- 可以通过msgget函数创建一个新的消息队列 ,或者获取一个已经存在的消息队列
- 通过msgsnd函数向消息队列的后端追加消息(需要把消息从用户空间拷贝到内核空间)
- 通过msgrcv函数从消息队列的前端按要求提取消息(需要把消息从内核空间拷贝到用户空间)
- 消息队列中的每个消息除了消息本身数据以外,还包含消息类型和数据长度
- 内核为每个消息队列 ,维护一个msqid_ds结构体形式的消息队列对象
#include <sys/msg.h>
//msgget 创建或者获取消息队列
int msgget(key_t key,int msgflg);
/*
A.该函数以参数key作为键值创建消息队列,如果存在则获取消息队列
B.msgflg标识
0 - 获取,不存在即失败
IPC_CREAT - 创建,不存在则创建,已存在则获取,除非 创建时需要给定权限 IPC|0644
IPC_EXCL - 排斥,创建时如果已经存在则创建失败
成功返回消息队列标识,失败返回-1
*/
//msgsnd向消息队列发送消息
int msgsnd(int msgqid,const void *msgp,size_t msgsz,int msgflg);
/*
A. msgqid 消息队列的标识 msgget函数的返回值
B. msgp参数是一个指针,指针指向一块内存,内存中包含消息类型和消息数据
内存中的前4/8个字节必须是一个大于0的整数,代表消息类型,其后紧跟消息数据
消息数据的字节长度用msgsz参数表示 注意:msgsz长度并不包含消息类型4/8个字节
+------------+--------------------+
msgp--> |消息类型(>0) | 消息数据 |
+------------+--------------------+
|<-4/8Byte-> |<----msgsz--------->|
C.若内核中消息队列缓冲区有足够的空闲空间,则此函数会将消息拷入缓冲区并立即返回0,表示发送成功,否则此函数会阻塞,直到内核中的消息队列缓冲区有足够的空闲空间为止(比如有消息被接收)
D.若msgflg参数包含IPC_NOWAIT位,则当内核中的消息队列没有足够空闲空间时,此函数不会阻塞,而是直接返回-1,且errno设置为EAGAIN
成功返回0 失败返回-1
*/
//msgrcv 从消息队列中接收消息
ssize_t msgrcv(int msgqid,void *msgp,size_t msgsz,long msgtype,int msgflg);
/*
A.msgqid 消息队列标识,msgget函数的返回值
B.msgp指针指向一个包含消息类型(4byte)和消息数据的内存块,用于存储消息类型和消息数据本身
C.msgsz参数用来标明消息数据缓冲区字节大小 msgp指针指向的内存块的大小-4/8byte
D.若所接收到的消息字节数据大于msgsz参数,即消息太长
E.如果msgflg参数中包含MSG_NOERROR位,则消息太长会被截取msgsz字节返回,剩余部分会被丢弃
如果msgflg参数不包含MSG_NOERROR五个,消息太长时,不会对该消息做任何处理,直接返回-1,且errno设置为E2BIG
F.msgtype参数表示期望接收哪类消息
msgtype = 0 - 返回消息队列中的第一条消息
m
|