Linux:简单理解System V -- 共享内存、消息队列、信号量


共享内存

本质原理: 多个进程要是映射同一块物理内存,就可以通过这块内存实现数据共享

  1. 在物理内存上开辟一块内存空间
  2. 多个进程可以将这块物理内存映射到自己的虚拟地址空间
  3. 通过虚拟地址进行页表映射直接访问这块物理内存,实现数据共享

特性:

  1. 最快的进程间通信方式
  2. 生命周期随内核

注意事项:

共享内存的操作是不安全的(并不会自动具备同步与互斥关系,需要操作用户进行控制)

操作: 代码操作流程/具体的接口+命令操作ipcs/ipcrm

为什么共享内存是最快的进程间通信方式?

对于管道这种通信方式,涉及到两次用户态与内核态之间的数据拷贝,将数据写入管道,从管道读取数据;对于共享内存这种通信方式,它是直接通过虚拟地址访问物理内存实现数据共享,相较于管道少了两次用户态与内核态之间的数据拷贝操作,因此速度最快。

注意: 共享内存没有同步和互斥特性,操作会存在安全隐患!!!

共享内存的生命周期:

随内核,在物理内存开辟空间,信息存储在内核;共享内存是属于内核的一个进程间通信的资源;不会随着进程的退出而退出;内核重启或者手动释放会释放该空间,否则一直存在于内核。

共享内存的操作流程:

  1. 创建共享内存(开辟物理空间—具有标识符)
  2. 将共享内存映射到各个进程的虚拟地址空间
  3. 直接通过虚拟地址进行内存操作
  4. 解除映射关系
  5. 删除共享内存

共享内存函数

  1. shmget函数
int shmget(key_t key, size_t size, int shmflg)

功能: 用来创建共享内存

参数:

  • key: 内核中共享内存的标识符,多个进程通过相同的标识符可以打开同一块共享内存
  • size: 共享内存大小 — 以内存页为单位进行分配
  • shmflg: IPC_CREAT - 存在则打开,不存在则创建 | IPC_EXCL 与 IPC_CREAT 同时使用,若存在则报错,不存在则创建 | 权限

返回值: 返回一个非负整数 - 共享内存的操作句柄,失败返回-1

生成一个key值:

key_t futon(const char *pathname, int prom_id) - 通过inode节点号与projid合成一个key
  1. shmat函数
void *shmat(int shmid, void *shmaddr, int shmflg);

功能: 将共享内存段连接到进程地址空间

参数:

  • shmid: shmget反回的共享内存标示
  • shmaddr:映射到虚拟地址空间的首地址,通常置 NULL,(指定连接地址)
  • shmflg: 映射成功之后对共享内存可以进行的操作 SHM_RDONLY-只读(前提是有读的权限)/ 0-默认可读可写

返回值: 成功返回共享内存映射的虚拟空间的首地址,通过这个地址对内存进行操作,失败返回-1

  1. shmdt函数
int shmdt(const void *shmaddr);

功能: 解除映射关系

参数:

  • shmaddr:映射到虚拟地址空间的首地址(shmat所返回的指针)

返回值: 成功返回0,失败返回-1

注意:

当删除共享内存的时候,共享内存并不会立即被删除,(因为有可能会造成正在访问的进程崩溃),只是将其状态置为被销毁状态,移除标示。(表示这块共享内存不再继续接受映射链接,当这块共享内存的映射链接数为0的时候,则才会真正被删除)

  1. shmctl函数
int shmctl(int shmid,int cmd, struct shmid_ds *buf)

**功能:**用于控制共享内存

参数

  • shmid:由shmget返回的共享内存标识码
  • cmd:对共享内存想要进行的操作 — IPC_RMID-删除共享内存
  • buf:用于获取/设置共享内存信息的结构,不使用则置NULL

返回值: 成功返回0;失败返回-1
在这里插入图片描述

操作系统中进程间通信资源的命令操作:

  • ipcs 查看进程间通信资源
  • -m 共享内存
  • -q 查看消息队列
  • -s 查看信号量
  • ipcrm 删除进程间通信资源(ipcrm -m shmid)

消息队列

本质:

内核中的一个具有标识符的优先级队列,多个进程通过向同一个队列中添加节点和获取节点实现通信

  • 消息队列提供了一个从一个进程向另外一个进程发送一块数据的方法
  • 每个数据块都被认为是有一个类型,接收者进程接收的数据块可以有不同的类型值

特性:

  1. 自带同步与互斥
  2. 生命周期随内核
  3. 数据传输自带优先级

注意事项:

struct msgbuf{ int type; char buf[***]}; 这个结构体需要用户自己定义
msgget     创建队列
msgsnd     添加节点
msgrcv     获取节点 

信号量

用于实现进程间的同步与互斥(共享内存本身是不提供同步与互斥的,操作存在安全隐患,因此需要使用信号量搭配)

  • 互斥:保证同一时间只有一个进程访问临界资源实现临界资源的互斥访问保证安全性
  • 同步:通过一种条件的判断,不能访问则等待,能访问再唤醒,实现对临界资源访问的合理性

本质:

内核中的计数器+pcb等待队列(对资源进行计数

同步的实现: 信号量是一个对资源的计数,可以通过计数判断是否能够获取一个资源进行处理;若计数 <= 0,则表示不能获取,则需要等待(加入pcb队列),这时候若其他进程生产一个资源,再唤醒;若计数 > 0表示能获取

互斥的实现: 通过只有0/1的计数器,实现对临界资源访问状态的标记;在访问临界资源之前先获取信号量,计数-1;若计数<0则使进程等待(将进程pcb加入队列中);否则则可以对临界资源进行访问并且在访问完毕之后,则对计数+1,唤醒一个进程(将一个pcb出队,置位运行状态)


如果本篇博文帮助到了您,留个赞呐~~

猜你喜欢

转载自blog.csdn.net/AngelDg/article/details/106802665
今日推荐