SystemV ipc(进程间通信)

本文介绍了消息队列和信号量在进程间通信中的原理,强调了它们作为共享资源管理和互斥访问的工具。通过信号量的PV操作实现原子性,确保数据一致性。同时,信号量被设计用于事件通知和进程间的协同,而非单纯的数据传输。
摘要由CSDN通过智能技术生成

消息队列原理

要通信,必须让不同进程看到同一份资源,这个资源可以是文件缓冲区,内存块
到了消息队列就是一个我们之前学习过的队列数据结构,但是我们自己写的队列用不了
所以
1.必须让不同进程看到同一个队列
2.允许不同的进程,向内核中发送带类型的数据块
这样A发A的 B发B的不会乱
在这里插入图片描述
消息队列的创建接口和销毁接口和共享内存差不多
在这里插入图片描述
消息队列的管理属性结构中同样维护了ipc_perm里面保存了key
在这里插入图片描述
,只不过发送和接受接口个性化,我们可以看到数据块结构体msgbuf需要自定义,其中定义了数据块的类型A或者B

在这里插入图片描述

可以看到信号量也同样在内核中维护了这种ipc_perm结构体,保存了key
在这里插入图片描述
IPC在内核中的数据结构设计
在操作系统中,所有的IPC资源,都是整合进操作系统的IPC模块(进程间通信模块)中的!
管理共享内存和消息队列和信号量就是管理以下三种结构,所以问题是该如何把这些数据都管理起来呢?
在这里插入图片描述
,OS中也是用数组来管理的,数组中保存了struct ipc_perm*
如果今天创建了一个共享内存,OS就会为我们创建struct shmid_ds结构,我们就把第一个字段struct ipc_perm shm_perm地址放入到数组当中,消息队列和信号量同理都把第一个字段地址放入数组中(这个道理就像你创建一个都是Int类型的结构体你看看第一个整形的结构体地址和结构体地址一不一样?)
从此往后管理所有IPC资源,先描述,对所有资源增删查改转化成对该数组增删查改!
这样我们就可以遍历数组,结合ipc_perm里面的Key确认共享内存是新是旧
ipc_perm所在数组中的下标就是shmid or xxxid,找到数组中下标了那属性也就找到,那就增删改查呗

数组中保存的是ipc_perm的地址,该如何访问共享内存or消息队列 shmid_ds 和msgid_ds中的其他属性呢?
强转成相应ds结构体地址就可以访问了!因为结构体地址和第一个字段地址一样,强转后当然可以访问了
在这里插入图片描述
那我怎么知道当前数组中地址是什么类型?是共享内存?消息队列?还是信号量?
OS中在ipc_perm中保存了相应的类型标志位,那OS也就知道该强转成什么类型了!
蓝线
在这里插入图片描述
这种技术不就是我们C++中的多态吗?
ipc_perm不就是基类啊,三种ipc的ds属性结构不就是子类啊
数组中保存基类地址指向子类,就是典型多态

子类继承基类时,基类是子类的第一个成员,所以构造时先父后子

在这里插入图片描述
所以未来你想用IPC资源,你只需要告诉我shmid就行了,他就去数组中去找
那为什么这个shmid数组下标为什么这么大呢?
这个shmid是线性递增的,你用完了之后再申请shmid仍然会变大,不给你原来用过的,但是也不会越界,它会回绕到数组最开始0
在这里插入图片描述
这个数组不像文件描述符和进程强关联,他被边缘化了,所以跟文件描述符下标从3开始很小有所区别


信号量

第一阶段

在这里插入图片描述
共享内存没有任何保护机制
当我们的A正在写入,写入了一部分,就被B拿走了,导致双方发和收的数据不完整-------数据不一致问题
1.A B看到的同一份资源,共享资源,如果不加保护,会导郅数据不一致问题
2.加锁–互斥访问–任何时刻,只允许一个执行流访问共享资源–互斥
我来写,你想读你就得在旁边等着等我写完了你再来,同样你再读的时候我也不会去写!
生活中比如ATM机,你去取钱门给你反锁你办完事再出来,下一个再进

所以共享内存不加保护只能叫做共享资源
3.共享的,任何时刻只允许一个执行流访问(就是执行访问代码)的资源–临界资源----一般是内存空间(管道还是队列还是共享内存不都是内存空间吗)
我们学习的管道就是临界资源

4.举例:100行代码,只有5~10行代码才在访问临界资源(比如往共享内存fgets之类)。我们访问临界资源的代码----临界区
在这里插入图片描述
以上4个概念可以解释一个现象
多进程,多线程 并发打印
比如有5个进程同时并发向显示器输出打印

显示器上的消息:1、错乱的 2、混乱的 3、和命令行混在一起
原因:
显示器是文件吗?是
既然是文件,那本质当我们向显示器写入,要先向显示器文件的缓冲区写入数据,然后OS才把数据刷新到显示器上最后你才看到
当多进程都像同一个显示器打印,前提条件是每个进程都得看到同一个显示器资源
所以显示器资源在多进程场景中本质就是一种共享资源,当我们都在打印时,你打你的,我打我的,我们彼此之间没有同步互斥保护机制,所以对应的显示器资源在写入时导致了数据不一致问题
所以你想不出现错乱,就必须把显示器资源变成临界资源
这就是最典型的数据不一致问题,这是正常现象

信号量第二阶段-理解信号量

信号量/信号灯的本质是一把计数器,类似但不等于int cnt = n

描述临界资源中资源数量的多少!
什么临界资源中资源数量?不理解

临界资源可以被划分成很多小块的资源,一块一块用
每个进程执行流只使用一小块资源,同时允许两个执行流都进来进行访问,提高多执行流访问临界资源的并发度,可以提高效率,只要保证你们访问的是不同块资源
在这里插入图片描述
我们最怕的是什么??多个执行流访问同一个资源、n+1个执行流,总共有n个资源块
这两种情况最终都会导致多个执行流访问同一个资源
所以我们可以引入一个计数器cnt申请时–释放时++来维护允许进入资源中执行流的数量,这样多执行流就可以并发访问了
在这里插入图片描述
1.申请计数器成功,就表示我具有访问资源的权限了
⒉申请了计数器资源,我当前访问我要的资源了吗? 没有。申请了计数器资源是对资源的预订机制
3.计数器可以有效保证进入共享资源的执行流的数量
4.所以每一个执行流,想访问共享资源中的一部分的时候,不是直接访问,而是先申请计数器资源。就好比看电影的先买票!
程序员把这个"计数器",叫做信号量!这个量可以理解为数量

假如今天资源作为一个整体使用,不分了,整体申请,整体释放!那么计数器就是1
这也就意味着任何时刻,只有一个执行流能访问临界资源,这就是互斥啊
我们把值只能为1,0两态的计数器 叫做 二元信号量 ----- 本质就是一个锁(互斥里面的加锁)

思考一下:
要访问临界资源,先要申请信号量计数器资源
信号量计数器 不也就是共享资源吗????
计数器保护临界资源只被一个执行流访问,得先保证计数器本身是安全的的,也就是不要让数据不一致发生在计数器身上

但这个cnt–计数器是不安全的,因为汇编语言会分成3条,cpu多进程切换时在这三条语句中某一句有可能被切走,切走了要么多减,要么少减,反正它会出问题
在这里插入图片描述
在这里插入图片描述

所以信号量就不能简单的cnt–而是封装了PV操作
申请信号量,本质是对计数器–,P操作
释放资源,释放信号量,本质是对计数器进行++操作,V操作
申请和释放PV操作是—原子的!——要么不做,要做就做完—两态的。没有“正在做”这样的概念!
从技术上说你的汇编语句执行时只有一条汇编语句,一条语句要么执行要么不执行,这条语句无法切割
生活中你的学习过程对你父亲来说他要么不知道你上大学,要么就已经知道了
信号量PV操作只有是原子的才能保证自己的安全,才能保护别人

总结:
信号量本质是一把计数器,PV操作,原子的。
执行流申请资源,必须先申请信号量资源,得到信号量之后,才能访问临界资源!!
信号量值1,0两态的,二元信号量,就是互斥功能
申请信号量的本质:是对临界资源的预订机制!! !

接口
多个信号量集合(很多个一把计数器放到数组里)和信号量是几(一个信号量计数器初始化成几)
在这里插入图片描述


信号量也不以互相传输数据为目的,信号量凭什么是进程间通信的一种?

1.通信不仅仅是通信数据,互相协同也是
协同虽然不是以传输数据为目的,但是他是以事件通知为目的,告诉你某件事发生了,计数器有你就进去用,没有你就等着,实现同步和互斥

⒉要协同,本质也是通信,信号量首先要被所有的通信进程看到!!
信号量基于这两点把信号量被OS设计者归纳到进程间通信的范畴


查查mmp函数
可以做到直接使用内存向文件中写入数据而不需要调用文件接口
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值