消息队列、共享内存和信号量被统称为 system-V IPC
一般习惯称呼他们为 IPC 对象,这些对象的操作接口都比较类似,在系统中他们都使用一种叫做 key 的键值来唯一标识,而且他们都是“持续性”资源——即他们被创建之后,不会因为进程的退出而消失,而会持续地存在,除非调用特殊的函数或者命令删除他们
Linux 的 IPC 对象(包括消息队列、共享内存和信号量)在内核内部使用链表维护,不同的对象使用 IPC 标识符来标识,如消息队列标识符 msqid、共享内存标识符 shmid,信号量标识符 semid。对于用户来说,内核提供了简洁的接口,不同的进程通过 IPC 关键字(key) 即可访问具体的对象
查询系统当前的 IPC 对象
ipcs
查看当前消息队列
ipcs -q
system-V ipc特点
1.独立于进程
2.没有文件名和文件描述符
3.IPC对象具有key和ID
消息队列
消息队列提供了一种从一个进程向另一个进程发送一个数据块的方法。每个数据块都被认为含有一个类型,接收进程可以独立地接收含有不同类型的数据结构。我们可以通过发送消息来避免命名管道的同步和阻塞问题
消息队列与信号的对比:
信号承载的信息量少,而消息队列可以承载大量自定义的数据
消息队列与管道的对比:
1.命名管道和消息队列进行通信的进程可以是不相关的进程,同时它们都是通过发送
和接收的方式来传递数据的
2.在命名管道中,发送数据用 write(),接收数据用 read(),则在消息队列中,发送数
据用 msgsnd(),接收数据用msgrcv(),消息队列对每个数据都有一个最大长度的限制。
3.消息队列也可以独立于发送和接收进程而存在,在进程终止时,消息队列及其内容
并不会被删除。
4.消息队列是面向记录的,其中的消息具有特定的格式以及特定的优先级,接收程序
可以通过消息类型有选择地接收数据,而不是像命名管道中那样,只能默认地接收
5.消息队列可以实现消息的随机查询,消息不一定要以先进先出的顺序接收,也可以
按消息的类型接收。
消息队列的实现包括创建或打开消息队列、发送消息、接收消息和控制消息队列这 4 种操作
消息队列相关API
ftok函数 作用:获取一个key
key_t ftok(const char *path,int proj_id)
path:一个合法路径
proj_id:一个整数
msgget函数 功能:获取消息队列ID
int msgget(key_t key,int msgflg)
key:消息队列的键值
msgflg:
IPC_CREAT:如果消息队列不存在,则创建
mode:访问权限
返回值:消息队列的ID
msgsnd函数 作用:发送消息到消息队列
int msgsnd(int msqid,const void *msgp,size_t msgsz,int msgflg);
msqid:消息队列ID
msgp:消息缓存区(发送给队列的消息)
msgp 可以是任何类型的结构体,但第一个字段必须为 long 类型,
即表明此发送消息的类型, msgrcv() 函数则根据此接收消息。
struct msgbuf
{
long mtype; //消息标识
char mtext[1]; //消息内容
}
msgsz:消息正文的字节数大小
msgflg:
IPC_NOWAIT:非阻塞发送
0:阻塞发送
msgrcv函数 功能:从消息队列读取消息
ssize_t msgrcv(int msqid,void *msgp,size_t msgsz,long msgtyp,int msgflg)
msqid:消息队列ID
msgp:消息缓存区
msgsz:消息正文的字节数
msgtyp:要接受消息的标识
msgflg:
IPC_NOWAIT:非阻塞读取
MSG_NOERROR:截断消息
0:阻塞读取
msgctl函数 功能:设置或获取消息队列的相关属性(删除,设置或这获取相关消息信息
int msgctl(int msgqid,int cmd,struct maqid_ds *buf)
msgqid:消息队列的ID
cmd:
IPC_STAT:获取消息队列的属性信息
IPC_SET:设置消息队列的属性
IPC_RMID:删除消息队列
buf:相关结构体缓冲区
信号量
信号量与信号、管道、 FIFO 以及消息列队不同。它本质上是一个计数器,用于协调多进程间对共享数据对象的读取,它不以传送数据为主要目的,它主要是用来保护共享资源(信号量也属于临界资源),使得该临界资源在一个时刻只有一个进程独享。
信号量的操作:PV操作
信号量只能进行两种操作:等待和发送信号,即 P 操作和 V 操作,锁行为就是 P 操作,解锁就是 V 操作,所以 P 操作是申请资源, V 操作是释放资源。
P 操作:
如果有可用的资源(信号量值大于 0),则占用一个资源
即给信号量值减去一,进入临界区代码
如果没有可用的资源(信号量值等于 0),则阻塞,直到系统将资源分配给该进程
(进入等待队列,一直等到资源轮到该进程)。
V 操作:
如果在该信号量的等待队列中有进程在等待资源,则唤醒一个阻塞的进程。
如果没有进程等待它,则释放一个资源,即给信号量值加一
信号量的作用
保护共享资源
互斥
同步
信号量用法:
1.定义一个唯一key(ftok)
2.构造一个信号量(semget)
3.初始化信号量(semctl SETVA)
4.对信号量进行P/V操作(semop)
5.删除信号量(semctl RMID)
semget函数 功能:获取信号量的ID
int semget(key_t key,int nsems,int semflg)
key:信号量键值
nsems:信号量数量
semflg:
IPC_CREATE:信号量不存在则创建
mode:信号量的权限
返回值:信号量ID
semctl函数 功能:获取或设置信号量的相关属性(删除 ,设置,获取)
int semctl(int semid,int semnum,int cmd,union semun arg)
semid:信号量ID
semnum:信号量编号
cmd:
IPC_STAT:获取信号量的属性信息
IPC_SET:设置信号量的属性
IPC_RMID:删除信号量
IPC_SETVAL:设置信号量的值
arg:可选参数
union semun
{
int val;
struct semid_ds *buf;
}
semop函数
int semop(int semid,struct sembuf *sops,size_t nsops)
semid:信号量ID
sops:信号量操作结构体数组
struct sembuf
{
short sem_num; //信号量编号 信号量的序号从 0 ~ nsems-1
short sem_op;//信号量P/V操作 >0 0 0:
表示进程对资源使用完毕,交回该资源,即对该信号量执行 V 操
作,交回的资源数由 sem_op 决定,系统会把 sem_op 的值加到该信号量的信号量当前值 semval 上
0:
表示进程要阻塞等待,直至信号量当前值 semval 变为 0
关注
打赏
最近更新
- 深拷贝和浅拷贝的区别(重点)
- 【Vue】走进Vue框架世界
- 【云服务器】项目部署—搭建网站—vue电商后台管理系统
- 【React介绍】 一文带你深入React
- 【React】React组件实例的三大属性之state,props,refs(你学废了吗)
- 【脚手架VueCLI】从零开始,创建一个VUE项目
- 【React】深入理解React组件生命周期----图文详解(含代码)
- 【React】DOM的Diffing算法是什么?以及DOM中key的作用----经典面试题
- 【React】1_使用React脚手架创建项目步骤--------详解(含项目结构说明)
- 【React】2_如何使用react脚手架写一个简单的页面?