【Linux】system V 共享内存
创始人
2025-01-20 06:33:23
0

文章目录

  • system V
    • 1. 共享内存原理
      • 第一阶段原理
      • 第二阶段原理
    • 2. 直接写代码--编写代码进行原理介绍
        • shmget函数
        • ftok函数
        • key值用法
      • 1. 创建key值
      • 2. 创建共享内存 获取共享内存
      • 3. 将自己和共享内存关联起来
      • 4. 将自己和共享内存取消关联
      • 5. 删除共享内存
        • 用指令删除
        • 调用系统调用
      • 完整代码
        • makefile
        • comm.hpp
        • server.cc
        • client.cc

system V

system V 是一套标准,独立于文件系统之外的,专门为了通信设计出来的模块
让两个毫不相关的进程看到同一份资源

1. 共享内存原理

第一阶段原理

在这里插入图片描述

进程A和进程B都通过自己的页表映射到物理内存中的特定区域,进而找到该进程匹配的代码和数据
为了让进程A和进程B通信,前提是两者要看到同一份资源
假设在物理内存上开辟一块空间
进程A和进程B在自己的地址空间中都有自己的共享区
想办法把物理内存中新开辟空间 通过页表 映射到 进程A和进程B的共享区中
把地址空间的起始地址返回给用户
进程A和进程B就可以通过起始的虚拟地址,对应页表访问到内存
就完成了让进程A和进程B看到同一份资源,这份资源就被称为共享内存

第二阶段原理

系统中可以用ssh进行通信 ,是不是只能有一对进程使用共享内存呢?
可以,其他进程也可以通信
所以在任何时刻,可能有多个共享内存在被使用
系统中一定会存在很多共享内存同时存在
操作系统要不要整体管理所有的共享内存呢?要
操作性系统如何管理多个共享内存呢?
先描述,在组织
并不是在内存中开辟空间即可,系统为了管理共享内存,构建对应的描述共享内存的结构体对象
共享内存=共享内存的内核数据结构(伪代码:struct shm)+真正开辟的内存空间

2. 直接写代码–编写代码进行原理介绍


打开vscode,创建文件client.cc和server.cc(后缀为cc说明是c++)的文件
创建公共路径 comm.hpp

shmget函数

创建共享路径接口 ,输入 man shmget 查看
在这里插入图片描述

申请一个 系统V的共享内存块
如果创建成功,则会返回共享内存标识符,失败返回-1


size代表申请内存块的大小
shmflg代表 选项
有两个最常用的选项,IPC_CREAT IPC_EXCL
转到定义就可以发现其实这两个都是宏


若单独使用 IPC_CREAT :创建一个共享内存,如果共享内存不存在,就创建之,如果已经存在,就获取已经存在的共享内存并返回
IPC_EXCL不能单独使用 ,一般都要配合 IPC_CREAT
若要将两个选项同时传进去 IPC_CREAT | IPC_EXCL
两个选项同时用: 创建一个共享内存,如果共享内存不存在,就创建之,如果已经存在,则立马出错返回
如果创建成功,对应的共享内存一定是最新的


获取共享内存时,需要有一个key值

ftok函数

输入 man ftok

根据路径和项目id进行算法结合,形成一个冲突概率低的key值
失败就返回-1,成功返回key值

key值用法

假设进程A创建了一个共享内存,但是进程B怎么知道那个共享内存是创建的吗?
就需要借助上述提到的 ftok 函数


在这里插入图片描述

刚开始约定好 A和B用同样的路径字符串和项目id
借助A形成一个key值,将key值放入A创建的共享内存描述结构体中
此时B也形成一个相同的key值,通过寻找key值来找到A所创建的共享内存


pathname 代表 用户自己设定的路径字符串
proj_id 代表 项目id
key值意义为
让创建共享内存的进程可以给新共享内存设置key值
让获取共享内存的进程 通过key值 去找特定匹配的共享内存

1. 创建key值

comm.hpp 公共路径中构建一个函数 Getkey 用于返回key值


在这里插入图片描述

构建一个函数 tohex,用于将数转换为十六进制


通过server.cc与client.cc中分别调用Getkey 与tohex函数


两者的返回值key 是相同的,并且返回的都是十六进制数

2. 创建共享内存 获取共享内存

在这里插入图片描述
创建共享内存,调用shmget函数,通过两个选项 若共享内存不存在则创建,若存在则报错
而获取共享内存,调用shmget函数,则返回已有的共享内存


此时运行可执行程序,发现server与client的shmid(共享内存标识符)相同

3. 将自己和共享内存关联起来

输入 man shmat 指令
在这里插入图片描述
at代表 关联
将共享内存和目标值关联起来
返回值为 共享内存的虚拟地址的起始地址
我们不知道应该把共享内存放在虚拟空间的什么地址处,所以shmaddr设为NULL让系统自主去选择
shmflg 可以设置为 SHM_RDONLY 表示当前共享内存是只读的 一般设为0,默认为读写的


4. 将自己和共享内存取消关联

输入 man shmdt 指令
在这里插入图片描述
shmdt代表 虚拟地址
成功返回0,失败返回-1

5. 删除共享内存

创建共享内存的进程已经早就退出了,但是共享内存还存在
确认共享内存存在: ipcs
ipc作为进程间通信的简写
ipc表示资源 s表示有多个资源

在这里插入图片描述
显出来的为ipc通信系统所支持的三种ipc通信策略
Message Queues 消息队列
Shared Memory Segments 共享内存段
Semaphore Arrays 信号量


ipcs - m 查看共享内存段

在这里插入图片描述
perms 代表权限
bytes 代表字节数
nattch 代表 有几个进程和当前进程是关联的

用指令删除

key是在操作系统中使用的,类似于文件的inode编号
shmid 类似于文件的fd
所以删除操作,是在用户层,应该用shmid

在这里插入图片描述


ipcrm -m shmid值 就可以删除共享内存
此时就没有 shmid为0的共享内存 存在了

调用系统调用

输入 man shmctl 指令

在这里插入图片描述
shmid 代表 共享内存描述符 即想对那个共享内存操作
cmd 代表 选项 即想做什么操作
IPC_STAT 获取当前共享内存的属性
IPC_SET 设置共享内存属性
IPC_RMID 标记这个段被释放
buf 代表 共享内存的属性

在comm.hpp下 设置删除共享内存的函数,在server.cc中调用函数 即可删除共享内存

完整代码

makefile
.PHONY:all all:server client  server:server.cc 	g++ -o $@ $^ client:client.cc 	g++ -o $@ $^ .PHONY:clean clean: 	rm -f server client   

如何使两个可执行程序运行,在上一篇文章提到过,点击查看:命名管道


comm.hpp
#ifndef _COMM_HPP_ #define _COMM_HPP_ #include #include #include #include #include #include #include #include #include using namespace std;  #define PATHNAME "."//.表示当前路径  路径字符串 #define PROJID 0x6666 //项目id const int gsize=4096; key_t getkey()//用于返回key值 {     key_t k=ftok(PATHNAME,PROJID);     if(k==-1)//失败     {        cout<    char buffer[64];    //将x以十六进制的形式传给buffer    snprintf(buffer,sizeof(buffer),"0x%x",x);    return buffer; }  static int  createshmhelper(key_t k,int size,int flag)//static修饰只在本文件有效 {         int shmid=shmget(k,size,flag);   if(shmid==-1)//创建失败   {     cout<     //带有两个选项 若不存在则创建,若存在则报错     return createshmhelper(k,size,IPC_CREAT |IPC_EXCL); }  int getshm(key_t k,int size) {     //若有共享内存,则返回已有的共享内存      return createshmhelper(k,size,IPC_CREAT ); }  char* attachshm(int shmid)//关联 {     char*start=(char*)shmat(shmid,NULL,0);//对应类型void* 所以需要强转      return start; }  void detachshm(char*start)//取消关联 {  int n=shmdt(start);  assert(n!=-1);  (void)n; }  void delshm(int shmid) {    int n=shmctl(shmid,IPC_RMID,NULL);    assert(n!=-1);//为-1就删除失败    (void)n; }   #endif  

server.cc
#include"comm.hpp" #include int main() {     //1. 创建key值   key_t k=getkey();//获取key值   cout<<"server:"<

client.cc
#include"comm.hpp"  int main() {   key_t k=getkey();//获取key值   cout<<"client key:"<

相关内容

热门资讯

第一分钟辅助挂!随意玩辅助(辅... 第一分钟辅助挂!随意玩辅助(辅助挂)教你教程(最初真的是有挂)是一款可以让一直输的玩家,快速成为一个...
第5分钟辅助!小程序微乐辅助软... 第5分钟辅助!小程序微乐辅助软件(辅助挂)果然存在有挂(详细辅助安装教程)1、任何小程序微乐辅助软件...
黑科技辅助“情怀手机麻将辅助器... 黑科技辅助“情怀手机麻将辅助器”外挂透视辅助助手(都是真的有挂)1、该软件可以轻松地帮助玩家将情怀手...
7分钟辅助!丽水都莱辅助(辅助... 一、丽水都莱辅助简介了解软件请加微:136704302丽水都莱辅助是一款在线扑克游戏平台,玩家可以在...
六分钟辅助挂!椰子大厅辅助脚本... 六分钟辅助挂!椰子大厅辅助脚本(辅助挂)原来是有挂(详细辅助揭秘教程)亲,关键说明,椰子大厅辅助脚本...
黑科技辅助“衢州都莱辅助器下载... 黑科技辅助“衢州都莱辅助器下载”外挂透视辅助助手(切实真的是有挂);暗藏猫腻,小编详细说明衢州都莱辅...
第2分钟透视!皮皮游戏辅助器(... 第2分钟透视!皮皮游戏辅助器(辅助挂)力荐教程(原来有挂)1、在皮皮游戏辅助器ai机器人技巧中,中转...
第五分钟了解!祺友互娱脚本(辅... 第五分钟了解!祺友互娱脚本(辅助挂)好像真的是有挂(详细辅助透明挂教程)暗藏猫腻,小编详细说明祺友互...
黑科技辅助“新上游辅助”外挂透... 黑科技辅助“新上游辅助”外挂透视辅助脚本(原来有挂);1、下载好新上游辅助辅助软件之后点击打开,先需...
3分钟透视!决战卡五星有辅助吗... 您好,决战卡五星有辅助吗这款游戏可以开挂的,确实是有挂的,需要了解加微【136704302】很多玩家...