深入Linux内核:IPC资源管理揭秘

一、了解 System V消息队列

System V消息队列和共享内存有很多相似之处,都是用来进程间通信的,只不过共享内存是从内存中申请了一块物理内存,而消息队列在内存中是以队列的形式存在的

进程A,B之间互相通信,A向B发送数据,数据就会写在一个数据块中,链入队列中,进程B向A发送数据,也是如此。那么,进程A,B怎么样才能够拿到对方发送给自己的数据呢

这就要对数据块进行标记了,用一个变量(mtype)来标记一下就可以知道是谁发送的数据了

所以,消息队列是一个进程向另一个进程发送有类型数据块的方式

可能会有很多的进程之间都会用消息队列进行通信,那么,有这么多的消息队列,OS也是要管理的

在用户层面也提供了一种结构体描述消息队列。我们来看一下。

在这里插入图片描述
在这里插入图片描述

接下来,就认识一下消息队列的接口。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

ipcs -q//查看消息队列
ipcrm -q //删除消息队列

发送数据和接收数据

在这里插入图片描述

有类型的数据块

在这里插入图片描述

可以看到,这些接口都是很相似的,这里不再做过多介绍。

二、System V 信号量了解

在了解信号量之前,我们需要对一些概念进行理解。

1 并发编程的概念

多个执行流(进程)能看到的同一份公共资源:共享资源

被保护起来的资源叫做临界资源

那么,什么叫做临界资源呢

比如:进程A,B之间要互相通信,A向共享资源写入数据,B也向共享资源写入数据,那么,在同一时间,有两个执行流访问同一份资源,岂不是会造成数据的混乱,所以需要对共享资源进行保护,保护起来的资源就叫做临界资源

保护的方式常见互斥和同步

任何时刻只允许一个执行流访问资源,叫做互斥

这就好比ATM,一次只能有一个人取钱。

多个执行流,访问临界资源的时候,具有一定的顺序性,叫做同步

比如:食堂阿姨打饭的时候,所有人都必须在窗口前进行排队。

系统中某些资源一次只允许一个进程使用,称这样的资源为临界资源或互斥资源

对于临界资源的访问,都是通过代码实现的,在进程中涉及到临界资源的程序叫临界区,不访问临界资源的代码叫做非临界区

所以,对共享资源的保护,本质是对访问共享资源的代码进行保护(毕竟临界资源的访问是通过代码实现的)

在这里插入图片描述

2. 信号量的理解

什么是信号量呢

举一个例子:有去过电影院的小伙伴吧,在进电影院之前,我们必须先买票,才能够进去电影院。可是电影院的位置是有限的,假设只有100个座位,那么,我们就只能卖出100张票,卖出一张票就做一次减法操作,如果卖多了,那就要将多买出的票回收,做一次加法操作。

买票的本质就是对资源的预定机制

所以,信号量的本质是一种描述临界资源数量的计数器,对资源的预定机制

如果这个电影院只有一个座位呢,那么,这个VIP座位一次就只能被一个人使用,那么,当这个座位未被售出时,信号量就应该为1,任何人都可以预定,售出后,信号量为0,别人不能使用,我们把它叫做二元信号量

利用这个二元信号量,不就可以实现互斥功能了嘛。

信号量分为:多元信号量、二元信号量

多元信号量:实现互斥或者同步功能

二元信号量:实现互斥功能

每一个人看电影都要去买票,那么每一个进程访问公共资源,就必须先申请信号量。所有的进程要申请信号量,就意味着所有的进程要先看到同一个信号量,那么信号量本身不就是共享资源了。那么将来对信号量做P(- -),V(++)操作,要如何保证信号量的安全呢?这就要保证P,V操作的原子性了

所有的进程都要看到同一个信号量,进程间通信的本质不就是让不同的进程看到同一份资源吗信号量也就属于IPC的范畴了

1.所有得System V资源,生命周期全部都随内核

2.所有的System V资源,都要被OS管理起来

三、内核是如何组织管理IPC资源的

那接下来我们就来分析下面的一张图。

在这里插入图片描述

我们要创建一个消息队列时,OS就给你分配一个msg_queue,创建共享内存时,OS就分配一个 shmid_kernel,创建信号量,就分配一个 sem_array,不知道大家有没有注意到,描述这三个的结构体第一个成员类型都是一样的,也就是 kern_ipc_perm,在OS内组织IPC资源是用一个kern_ipc_perm* ipc_id_ary[]的数组管理的,这个数组根本就不是指向 kern_ipc_perm的,而是指向msg_queue或者shmid_kernel或者sem_array中的第一个成员,找到数组中未使用的一个下标填入这些结构体中第一个成员的地址获取地址时,第一个成员的地址和结构体的地址在数字层面上是相等的

将来要访问其中的某一个结构体中的第一个成员,只需要找到数组下标进行访问就可以了,那如果要访问一个结构体中的所有成员呢?我们只需要将这个地址强转成这个结构体的地址,不就可以进行访问了吗!
在这里插入图片描述
注意到第二个成员了吗?有人认识吗。这是柔性数组在计算该结构体的大小时,不会将柔性数组的大小计算在内,所以该结构体的大小是4字节,未来需要多大的空间我们就可以动态申请 malloc 空间,这样就比较灵活。毕竟OS不知道我们有多少共享资源,空间给多了就浪费了,给少了又不够,这样就可以随时随地的申请空间了。

还记得我们之前调用的 shmget 函数吗,它的返回类型是 int ,这个整型代表的就是共享资源在 ipc_id_ary结构体数组中的下标

在这里插入图片描述

shmid就是数组下标

在这里插入图片描述

这是一个全局的结构体OS通过这个结构体中的 entries找到 ipc_id_ary,就可以访问共享资源了

在这里插入图片描述

调用 ftok 函数形成的键值就被放在了这个结构体里面,两个进程通过 ipc_id_ary找到共享资源的结构体,然后通过相同的键值判断是否是同一个共享资源

在这里插入图片描述

以双链表的形式管理消息队列

在这里插入图片描述

在这里插入图片描述

今天的文章分享到此结束,觉得不错的给个一键三连吧。

评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值