IPC进程间通信-system V 共享内存

news2024/11/23 15:09:12

🧸🧸🧸各位大佬大家好,我是猪皮兄弟🧸🧸🧸
在这里插入图片描述

文章目录

  • 一、共享内存原理
  • 二、共享内存的建立原理
  • 三、共享内存的创建
  • 四、共享内存的删除
  • 五、共享内存挂接到自己的地址空间
  • 六、从进程地址空间去掉与共享内存的关联
  • 七、共享内存完整过程代码
  • 八、对于建立好共享内存之后的通信
    • 访问共享内存方法
  • 结论
    • 进行共享内存的访问控制

除了上次说的管道之外,还有system V的通信方案

system V有三种方式
① 消息队列(太陈旧,不考虑)
② 共享内存
③ 信号量

今天之说共享内存

一、共享内存原理

先回顾一下动态库,动态库是运行时库,在运行时才进行加载,而在使用动态库的地方保存的是偏移量,动态库加载后,各个使用动态库的程序都会根据加载的起始地址计算出使用到的函数和变量的地址。这些都在地址空间的共享区建立了映射,一个动态库可以被多个程序使用,所以也叫共享库。

那操作系统自己申请了一部分空间,将这一部分空间,通过页表,映射到申请的空间,然后页表返回这一部分空间的起始地址,那上层就拿到了这样一个虚拟地址,同样的,可以映射给另一个进程,这样就可以同时访问到这部分空间(共享,所以一般,共享内存,共享库,等等都是建立在堆栈之间的【共享区】)

1.申请空间
2.建立映射
就能够指向同一块内存了,达成了IPC的前提条件

二、共享内存的建立原理

共享内存是属于OS的,因为是OS创建的共享内存
共享内存是操作系统专门设立的一个内存模块,专用于IPC,所以这个模块就称为system V版本的进程IPC

管道是基于文件的读取方式上,恰巧能完成IPC,因为文件有读写的功能,而共享内存是专门为了IPC设计的,一定就决定了操作系统要提供一些功能或者接口,而且它属于操作系统

其次,如果很多进程都要通信,那就需要大量的共享内存,操作系统就要将他们管理起来

共享内存 = 共享内存块 + 对于的共享内存的内核数据结构
所以用链表等等数据结构管理起来,那么对于共享内存的管理,就变成了对特定数据结构的增删查改

三、共享内存的创建

但是共享内存有点不符合Linux下一切皆文件的概念,因为是一套独立的接口,所以后续用的并不多,但是OS也支持

shmget(shared memory segment)共享内存段
在这里插入图片描述

int shmget(key_t key,size_t size,int shmflg);

参数的解释:
①key
共享内存创建好了,对于要通信的双方能够看到,并且看到的是属于它的共享内存
这时候我们需要用key开保证,key是多大不重要,只要能够保证在系统唯一即可,比如服务端server和客户端client使用一个key,就可以看到同一个共享内存,就可以IPC
在这里插入图片描述
第一个参数就只会一个路径,但是这个路径一定要有权限
第二个参数项目id随便写(要求0-255,但是超过了会截断)
ftok不进行任何的系统调用,内部仅仅是一套算法,算出基本上的唯一值(极小概率重复,所以有了ftok也不一定就会创建成功,其实哈希算法也挺好的)

②size,顾名思义,共享内存段大小
最好是页的整数倍,一PAGE的大小是4K -> 4096
但是开其他大小也不影响,但是操作系统管理内存的时候,采用的是分段式和分页式的技术,就算申请4097,分配的也是8K,而且多出来的你不用,别人也用不了,纯纯浪费空间

③shmflg
常见选项有两种

IPC_CREAT
IPC_EXCL
①单独使用IPC_CREAT的话,如果底层已经存在该共享内存,会直接获取它,并返回,如果不存在,则创建它,并返回
②单独使用IPC_EXCL没有意义
③IPC_CREAT和IPC_EXCL一起使用,如果底层存在,出错返回,如果不存在,创建
④如果shmflg是0,那么默认是IPC_CRETE

shmget的返回值是共享内存的用户层标识符(类似于文件描述符)

#include <sys/ipc.h>
#include <sys/shm.h>
int main()
{
	key_t k = ftok(PATH_NAME,PROJ_ID);
	//path和项目id,自己设定
	assert(k!=-1);//k==-1就是唯一的key生成失败
	
	//创建共享内存
	int shmid = shmget(k,SHM_SIZE/*宏*/,IPC_CREAT|IPC_EXCL);
	//建议生成一个全新的共享内存,因为他是通信的发起者
	if(shmid ==-1)
	{
		perror("shmget");
		exit(1);
	}
}

四、共享内存的删除

我们发现,创建成功,当进程运行结束时,我们的共享内存还存在

ipcs -m //查看IPC ipcs就是查看总舵的ipc资源,-m就是memory共享内存
//手动删除
ipcrm -m shmid //删除ipc资源,是通过shmid来删除的
//代码删除
shmctl //shared memory control;

在这里插入图片描述
perms是permissions权限
我们可以看到,刚刚创建出来的共享内存是没有权限的,所以int shmid = shmget(k,SHM_SIZE,IPC_CREAT|IPC_EXCL|0666);
在后面加上权限,这样来创建

在这里插入图片描述

int shmctl(int shmid,int cmd,struct shmid_ds*buf);
//cmd有很多选项,删除共享内存用的是 IPC_RMID
//buf我们设为nullptr就可以了

想要使用共享内存
①申请共享内存
②在系统当中进行映射,ipcs -m中nattch表示有n个和共享内存关联

五、共享内存挂接到自己的地址空间

shmat (shared memory attach关联,贴上)
在这里插入图片描述

①第一个参数就是shmid(共享内存的用户层标识)

②第二个参数是挂接的地址,我们设为nullptr,让操作系统自动挂接,本来是需要传挂机在进程地址空间的哪个位置,但是不推荐自己挂,我们不容易分清楚情况,OS非常清楚,除非有特殊人的用途才需要我们自己挂接

③第三个参数是挂接方式,设为0,默认就挂机好了以读写的方式

但其实shmat这个接口最重要的是它的返回值,返回的是共享内存段的address(虚拟地址),失败返回-1
在这里插入图片描述

六、从进程地址空间去掉与共享内存的关联

在这里插入图片描述
attach是挂接
shmdt是shared memory detach,取消挂接

int shmdt(const void*shmaddr);
//从这个参数的形式,我们很容易想到shmat的返回值
//也就是说,我传共享空间的地址过去就可以取消挂接了

七、共享内存完整过程代码

//头文件....
string TransToHex(key_t k)//转十六机制
{
	char buffer[32];
	sprintf(buffer,sizeof buffer,"0x%x",k);
	return buffer;
}

//全大写的都是宏
int main()
{
	//创建公共的相同key
	//相同的算法,相同的数据源,算出相同的key
	key_t k = ftok(PATH_NAME,PROJ_ID);
	assert(k!=-1);
	//日志,这个可以不用管
	Log("Create key done",Debug)<<"server key : "<<TransToHex(k)<<endl;
	
	//创建共享内存
	int shmid = shmget(k,SHM_SIZE,TCP_CREAT|TCP_EXCL|0666/*权限是八进制*/);
	if(shmid == -1)
	{
		perror("shmget");
		exit(1);
	}
	Log("Create shm done",Debug)<<" shmid : "shmid<<endl;
	
	//挂接
	char*shmaddr = (char*)shmat(shmid,nullptr,0);//挂接地址操作系统绝对,方式默认是读写(传0);
	Log("Create shm done",Debug)<<" shmid : "shmid<<endl;

	//通信
	...

	//去挂接
	int n = shmdt(shmaddr);
	assert(n!=-1);
	(void)n;//避免告警
	Log("Detach shm done",Debug)<<" shmid : "shmid<<endl;

	sleep(10);
	//删除共享内存 shmctl
	int m = shmctl(shmid,IPC_RMID,ullptr);//删除shmid的共享内存
	//shmid是共享内存的用户级标识
	assert(m!=-1);
	(void)m;
	Log("Delete shm done",Debug)<<" shmid : "shmid<<endl;
	return 0;
}

八、对于建立好共享内存之后的通信

①首先,共享内存是被映射在共享区的,共享区是属于用户空间的,也就是说,这部分空间用户拿到了,可以不通过系统调用,直接访问 (双方要进行通信,直接进程内存级的读和写,不用经过任何函数)

②在之前调用管道的时候,我们建立好管道任然需要去read,write通过系统调用去IPC,因为用的是管道,而文件是属于内核当中的一种特定数据结构(操作系统:进程管理,内存管理,文件管理,驱动管理),所以文件是OS去维护的,所以他是在3G~4G空间范围内的,属于内核空间,用户无法直接进行访问。
而共享内存是创建在堆栈之间的,它属于用户空间,所以不需要调用系统调用,直接访问

访问共享内存方法

我们可以将共享内存看成是一个大的字符串

某一端读取:

printf("%s\n",shmaddr);
//直接就可以打印出共享内存中的内容

另一端写:

snprintf(shmaddr,SHM_SIZE-1,"hello server,我是其他进程,我的pid是:%d",getpid());

在这里插入图片描述

结论

①主要是通信双方都是用shm,一方向共享内存写入数据,另一方就可以立马看到对方写入的数据,
所以说共享内存的IPC是所有IPC中最快的。因为不需要过多的拷贝(表现就是不需要将数据交给OS)

在这里插入图片描述

②在管道中,管道是提供了访问控制的,而共享内存缺乏访问控制!共享内存天然就是为了让我们快速进行通信的一种机制,所以内部没有提供任何的访问控制,比如shm都没有数据,但是也能读取,不过读到的是空串,可能双方进程都不知道对方的存在。

正因为共享内存缺乏访问控制,那么就会带来并发问题,比如我想写完了你再去,而不是拿一半数据就跑,这样的出来的结果是未定义的,会导致数据不一致问题

进行共享内存的访问控制

那此时如果我想进行一定的访问控制呢》
我们可以通过复用管道来实现共享内存同步的过程

具体做法就是向共享内存写,但是让对方先等待,就是使用管道,让对方去等待管道的数据(访问控制,控制读取的长度),等到了再往后执行,我们也可以用到RAII的思想来控制管道的析构

还是那个问题,共享内存的IPC用的并不多,是独立的一套接口,不符合Linux的一切皆文件观点,无法兼容后序的网络服务,后面有更强大的通信方式,而且通信手段也特别多

最后一个问题就是共享内存不做同步和互斥的处理是很容易出现问题的,非常容易数据不一致

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/154739.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

快过年了用Python抢红包

快过年了&#xff0c;刚刚收到了两个消息&#xff0c;一个好消息&#xff0c;一个坏消息。 先说好消息&#xff0c;好消息就是微信群里即将有人要发红包&#xff0c; 坏消息是我抢不上&#xff01; 难道就这么放弃了吗&#xff1f;那就只能试试能不能通过编程的方式实现自动化…

基于轻量级YOLOV5+BIFPN的苹果瑕疵检测识别分析系统

BIFPN是一种比较经典有效的特征融合手段&#xff0c;在很多检测模型中都有集成应用&#xff0c;实际表现也验证了BIFPN的有效性&#xff0c;这里并不是要探讨BIFPN的原理内容&#xff0c;而是想集成这项技术&#xff0c;提升原有模型的性能表现&#xff0c;在我之前的一些文章中…

排序算法之冒泡排序

一般学习过编程的人都知道&#xff0c;排序算法有很多种&#xff0c;包括直接选择排序、直接插入排序、计数排序、快速排序、归并排序、冒泡排序等&#xff0c;在我看来&#xff0c;以上六种排序算法是必须要掌握的&#xff0c;今天&#xff0c;我们先来讲解一下冒泡排序算法&a…

Java高手速成 | 新增类Record的工作实例

01、什么是Record? Record 是Java新增的库类&#xff0c;在Java 14和Java 15中以预览&#xff08;preview&#xff09;形式公布。Record类用来自动生成对定义数据进行创建、设置、访问以及比较等代码&#xff0c;所以又被称作数据类&#xff08;data class&#xff09;。在一…

初级开发者福音:手把手教你实现数字滚动效果~

文章目录一、前言二、背景知识三、实现方案Step 1&#xff1a;分析需求Step 2&#xff1a;实现单个数字的滚动效果Step 3&#xff1a;组件接口设计Step 4&#xff1a;完善组件一、前言 前端数字滚动显示的场景很多&#xff0c;比如抽奖的时候&#xff0c;营造一种马上公布中奖…

[MySQL从入门到实战环境部署](超详细版)

MySQL从入门到实战环境部署1.部署CentOS1.1部署CenOS虚拟机步骤&#xff08;1&#xff09;基于VirtualBox&#xff08;2&#xff09;下载CentOS1.2环境部署过程2.部署MySQL1.部署CentOS 1.1部署CenOS虚拟机步骤 &#xff08;1&#xff09;基于VirtualBox 下载网址&#xff1…

Docker Compose:Docker Compose部署nacos初始化MySQL

Docker Compose&#xff1a;Docker Compose部署nacos初始化MySQL找初始化sql文件nacos初始化mysql-schema.sql文件内容docker-compose.yml上传到挂载目录运行docker-compose.yml访问nacos找初始化sql文件 先去官网下载nacos安装包 官方github地址&#xff1a;https://github.…

Centos7安装opengauss

安装包下载地址&#xff1a;https://www.opengauss.org/zh/download/注&#xff1a;本文介绍的是轻量版安装先创建一个系统用户&#xff08;opengauss数据库不允许使用 root 用户安装&#xff09;创建用户useradd omm设置密码passwd omm将安装包拷贝并解压到用户家目录 ~/openG…

linux-云服务器数据盘挂载失败导致进入维护模式

已经在华为云、AWS上面吃过这个亏了&#xff0c;老这样可不好&#xff0c;心怦怦跳的。 华为云是由于服务器升级配置后重启&#xff0c;数据盘名称变化导致进入维护模式。AWS则是由于重启后没有挂载上数据盘&#xff0c;手动编辑/etc/fstab文件错误导致进入维护模式。 究其原…

2022年航空发动机行业研究报告

第一章 行业概况 航空发动机制造指主要用来产生拉力或推力使飞机前进的发动机设备。除了产生前进力外&#xff0c;还可以为飞机上的用电设备提供电力&#xff0c;为空调设备等用气设备提供气源。航空发动机制造产业链包括原材料研发、零部件生产制造、分系统和整机制造。 原材…

大智慧同花顺Level2行情数据有什么用

股市L2是大智慧Level2数据。由“上海证券交易所”最新推出的实时行情信息收费服务&#xff0c;主要提供在上海证券交易所上市交易的证券产品的实时交易数据。该行情速度比传统行情快3秒以上&#xff0c;同时包括十档行情、买卖队列、逐笔成交、总买总卖和统计信息等多种新式数据…

Fabric.js 拖放元素进画布

本文简介 点赞 关注 收藏 学会了 学习 Fabric.js&#xff0c;我的建议是看文档不如看 demo。 本文实现的功能&#xff1a;将元素拖进到画布中并生成对应的图形或图片。 效果如下图所示&#xff1a; 思路 要实现以上效果&#xff0c;需要考虑以下几点&#xff1a; 元素有…

婴儿游泳池行业市场经营管理及未来前景展望分析

2023-2029年中国婴儿游泳池行业市场经营管理及未来前景展望报告报告编号&#xff1a;1691316免费目录下载&#xff1a;http://www.cninfo360.com/yjbg/qthy/ly/20230109/1691316.html本报告著作权归博研咨询所有&#xff0c;未经书面许可&#xff0c;任何组织和个人不得以任何形…

PyQt6快速入门-事件处理

事件处理 文章目录 事件处理1、Qt事件介绍2、常用事件函数2.1 paintEvent事件2.2 鼠标事件2.3 窗口大小改变事件2.4 窗口隐藏/关闭/显示事件2.5 键盘按键事件3、事件拦截4、事件过滤器5、事件队列与事件处理1、Qt事件介绍 Qt GUI应用程序的核心是 QApplication 类。 每个GUI应…

Linux 文件 I/O

1.Linux 应用编程中最基础的知识&#xff0c;即文件 I/O&#xff08;Input、 Outout&#xff09; &#xff0c; 文件 I/O 指的是对文件的输入/输出操作&#xff0c;说白了就是对文件的读写操作&#xff1b; Linux 下一切皆文件&#xff0c;文件作为 Linux 系统设计思想的核心理…

java Lambda表达式引用类方法

Lambda表达式和方法引用是一对孪生兄弟 而引用类方法是Lambda支持的方法引用中的一种 引用类方法其实就是引用类的静态方法 直接上代码 首先 我们要创建一个包 包下创建一个接口 我这里叫subInterface 参考代码如下 public interface subInterface {int convelutl(String s…

【RabbitMQ】SpringBoot整合RabbitMQ

文章目录搭建初始环境引入依赖配置配置文件HelloWorld模型使用Work模型使用Fanout 广播模型Route 路由模型Topic 订阅模型(动态路由模型)搭建初始环境 引入依赖 <!--引入与rabbitmq集成依赖--> <dependency><groupId>org.springframework.boot</groupId…

NKOJ P3549 可见的点

分析 这道题乍一看是一道几何,实际上,是一道法雷数列模板题; 首先,他让我们求有多少条可见的线,实际上是让我们求有多少种不同的斜率可以存在,而斜率就是表现为yx\Large\frac{y}{x}xy​的形式;可以发现,只有当yx\Large\frac{y}{x}xy​为最简分数时,才能算作一条可见的线,其他…

Linux中如何使用Htop监控工具?【网络安全】

一、Htop界面展示 “Htop是一个用于Linux/Unix系统的交互式实时进程监控应用程序&#xff0c;也是top命令的替代品&#xff0c;它是所有Linux操作系统上预装的默认进程监控工具。 Htop还有许多其他用户友好的功能&#xff0c;这些功能在top命令下不可用 在Htop中&#xff0c;…

蓝桥杯省赛习题练习(二)

题目来源&#xff1a;2020年真题题集&#xff08;B组&#xff09; 注&#xff1a;代码都是自己写的&#xff0c;不是参考答案&#xff01; 目录1. 门牌制作运行结果2. 既约分数运行结果3. 蛇形填数运行结果4. 跑步锻炼运行结果5. 7段码6. 成绩统计运行结果7. 回文日期1. 门牌制…