个人主页:仍有未知等待探索-CSDN博客
专题分栏: Linux
目录
编辑
一、共享内存
1、原理
理解:
2、操作+具体理解
1.概括
2.创建共享内存
共享内存的生命周期?
key是什么?
进程怎么知道,共享内存是否存在?
shmget的返回值?
其他进程是怎么知道用户设置的key?
3.共享内存挂接到地址空间
数据安全(*)
4.内存空间的管理
二、消息队列
1、原理
2、接口
发送消息和接收消息
生命周期
三、信号量
1、五个概念
2、对于信号量的理论的理解
信号量对共享内存进行访问的过程:
信号量的分类:
信号量能用一个全局的变量进行替代吗?
数据安全:
3、信号量的操作
1.创建
2.管理
3.操作
四、共同点
os是如何吧对应的共享内存,消息队列,信号量统一管理起来的?
一、共享内存
1、原理
理解:
- 上述的操作都是os完成的。
- os必须提供对应步骤的系统调用。
- 共享空间可以在系统中存在很多份,供不同的进程同时进行通信。
- os要对共享内存进行管理。先描述再组织。共享内存,不是简单的一段内存空间,也要有描述并管理共享内存的数据结构和匹配的算法!
- 共享内存 = 内存空间(数据)+ 共享内存的属性。
共享内存不提供对共享内存的任何保护机制。
共享内存生命周期随内核,文件生命周期随进程。
2、操作+具体理解
1.概括
2.创建共享内存
#include <sys/ipc.h> #include <sys/shm.h> int shmget(key_t key, size_t size, int shmflg); --- 创建共享空间 // 函数的返回值是shmid是共享内存在用户层面的标识符,是一个整数。 // key:用户设置的标识符,标识共享内存,要有唯一性。 // size:共享内存的大小,建议设置成4096的整数倍 // shmflg:共享内存的权限 // IPC_CREAT:如果要创建的共享内存不存在,创建;如果存在,获取共享内存并返回。 --- 用来获取 // IPC_EXCL:单独使用没有意义。 // IPC_CREAT | IPC_EXCL:如果要创建的共享内存不存在,创建;如果就存在,出错返回。 --- 用来创建 #include <sys/types.h> #include <sys/ipc.h> key_t ftok(const char *pathname, int proj_id); --- 形成key // pathname:创建共享内存的路径 // proj_id:项目号,自定义设置,没有要求
创建的时候需要加上共享内存的权限,类似于:IPC_CREAT | IPC_EXCL | 0666。
共享内存的生命周期?
共享内存的生命周期随系统,而不是进程。
key是什么?
标识共享内存的编号。
进程怎么知道,共享内存是否存在?
如果是os创建key值得话,本地进程知道,其他进程获取不到。所以要自己设置key值,key值也要具有唯一性。
通过查找key值存不存在就知道对应的共享内存是否存在。
shmget的返回值?
返回用户层面的共享内存标识符(shmid)。
- shmid用于对共享内存进行操作。
- key用于查找共享内存是否存在。
其他进程是怎么知道用户设置的key?
通过同样的规则,利用ftok系统调用。
3.共享内存挂接到地址空间
#include <sys/types.h> #include <sys/shm.h> void *shmat(int shmid, const void *shmaddr, int shmflg); --- 挂接 int shmdt(const void *shmaddr); --- 去挂接
数据安全(*)
共享内存不提供对共享内存的任何保护机制 --- 会造成数据不一致问题。
共享内存是所有进程IPC速度最快的,因为共享内存大大减少了数据的拷贝次数!
共享内存的大小是4096的整数倍。
4.内存空间的管理
#include <sys/ipc.h> #include <sys/shm.h> int shmctl(int shmid, int cmd, struct shmid_ds *buf);
- cmd是对内存空间管理的各种选项:
- buf是存储的内存空间的属性。如果是要获取共享内存状态,buf是输出型参数;如果是要修改共享内存状态,buf是修改完成的共享内存状态,然后底层会把buf拷贝到内核中。
二、消息队列
1、原理
一个进程,向另一个进程发送有类型的数据块的方式。
2、接口
接口都是类似于共享内存的。
发送消息和接收消息
#include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h> int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg); ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,int msgflg); const void*msgp:发送的消息数据块的地址。 struct msgbuf:消息队列数据块。 struct msgbuf { long mtype; char mtext[1]; }
生命周期
消息队列的生命周期随系统。
三、信号量
1、五个概念
- 共享资源:多个执行流(cpu)能看到同一份资源。
- 临界资源:被保护起来的资源。(保护的方式,同步和互斥)
互斥:在任何时刻,只能有一个进程在访问共享资源。
资源:只要是资源就要被程序员访问的。--- 资源被访问,就是通过代码访问(朴素)代码 = 访问共享资源的代码(临界资源) + 不访问共享资源的代码(非临界资源)。
所谓的对共享资源的保护,本质是对访问共享资源的代码进行保护。(这里的共享资源就是临界区)
2、对于信号量的理论的理解
- 信号量是用来保护临界资源的。
- 信号量的本质是一个计数器。
类似于电影院买票:
电影院:共享资源(临界资源)
买票:申请信号量。--- 如果某场电影没有票了,就意味着,信号量为0,不能被申请。
票数:信号量的初始值。
申请信号量本质:就是对公共资源的一种预定机制。
信号量对共享内存进行访问的过程:
1、申请信号量。计数器减减操作。
2、访问共享内存。
3、释放信号量。计数器加加操作。
信号量的分类:
多元 和 二元。
二元信号量(类比超级vip):只有 1 or 0 --- 互斥。对共享资源进行整体使用。
多元信号量:网吧中的电脑,对于电脑,有很多台,其信号量大于2。
信号量能用一个全局的变量进行替代吗?
信号量不能用一个全局变量gcount当计数器。
1、全局变量不能被所有进程看到。
2、gcount不是原子。
数据安全:
IPC信号量和共享内存,消息队列一样,也必须先让不同的进程看到同一个“计数器”!--- 意味着信号量也是一个公共资源!! --- 保护临界资源安全的前提是信号量是安全的。
-- -> 安全的 -> P操作
++ -> 安全的 -> V操作
PV --- 安全 --- 原子性
3、信号量的操作
允许用户一次申请多个信号量。
信号量集 --- 用数组来维护。
1.创建
#include <sys/types.h> #include <sys/ipc.h> #include <sys/sem.h> int semget(key_t key, int nsems, int semflg);
这些参数和共享内存的一样的含义。
2.管理
#include <sys/types.h> #include <sys/ipc.h> #include <sys/sem.h> int semctl(int semid, int semnum, int cmd, ...);
3.操作
#include <sys/types.h> #include <sys/ipc.h> #include <sys/sem.h> int semop(int semid, struct sembuf *sops, size_t nsops); sem_op == 1,就是加加操作。 sem_op == -1,就是减减操作。
sops是个结构体,包含下列的属性。
四、共同点
1、划分为同一个标准:system V。
2、XXXget,XXXctl,生命周期随系统的。
3、都有XXXid_ds的struct结构,第一个属性都是struct ipc_perm;
os是如何吧对应的共享内存,消息队列,信号量统一管理起来的?
谢谢大家!