systemV共享内存
systemV共享内存
共享内存区是最快的IPC形式。共享内存的大小一般是4KB的整数倍,因为系统分配共享内存是以4KB为单位的(Page)!4KB也是划分内存块的基本单位。
之前学的管道,是通过文件系统来实现让不同的进程看到同一份资源,那有没有不通过文件来实现进程间通信的呢?有!MMU这些
原理
PCB、进程地址空间、页表是每个进程各有一份的【这部分是进程】,文件系统是一个独立的,对进程来说只有一份。

操作步骤:
- 创建共享内存:为了实现进程间通信,用户通过系统调用接口在物理内存申请一块内存空间[物理内存块+共享内存相关属性struct_shm]
- 进程和共享内存挂接:系统将创建好的内存映射到进程的地址空间,然后交给对应进程的PCB-task_struct。
- 断开通信的操作:a.去关联:先取消映射关系;b.释放内存:释放该块物理内存。
malloc能申请物理内存的空间,也能为某进程创建单一的映射关系,为什么不用它呢?
malloc是做不到的!因为malloc出来的映射关系是单一的,不同的malloc之后返回的起始地址都是不一样的,无法共享。
要明确把握的概念
- 共享内存是一种进程间通信方式,不是内存!所有想通信的进程都可以采用。
- 操作系统在同一时间可以存在很多的共享内存。
- 共享内存是专门设计的用于IPC的,故有专门的接口。
概念
让不同的进程看到同一块内存空间。
查看ipc-systemV资源的指令
查看ipc资源ipcs -m-m表示共享内存,-q消息队列
[yyq@VM-8-13-centos 2023_02_27_SharedMemory]$ ipcs -m------ Shared Memory Segments --------
key shmid owner perms bytes nattch status
systemV版本的共享内存的生命周期是随OS的,不随进程!所以一定要记得及时释放资源。注意:消息队列等方式的共享内存就是随进程的。
命令行删除共享内存ipcrm -m shmid
while :; do ipcs -m; sleep 1; done
函数接口
ftok()函数 得到key
#include <sys/types.h>
#include <sys/ipc.h>
原型key_t ftok(const char *pathname, char proj_id);//路径名的指针pathname,自己写的8bits的非0数字proj_id
返回值成功返回一个key值;失败返回-1
Today proj_id is an int, but still only 8 bits are used. Typical usage has an ASCII character proj_id, that is why the behavior is said to be undefined when proj_id is zero.
key保证进程看到同一块共享内存!能进行唯一性标识。key就是32位的int。
shmget()函数 得到shmid
#include <sys/ipc.h>
#include <sys/shm.h>
功能:用来创建共享内存
原型int shmget(key_t key, size_t size, int shmflg);
参数key:ftok()函数返回值,是共享内存段名字,保证该块共享内存的唯一性size:共享内存大小shmflg:由九个权限标志构成,它们的用法和创建文件时使用的mode模式标志是一样的IPC_CREAT 如果共享内存不存在,就创建;存在,则返回地址IPC_EXCL 无法单独使用,要与IPC_CREATE一起用。如果共享内存不存在,就创建;如果存在,就出错返回-->如果创建成功,就一定是一个新的共享内存
返回值成功返回一个非负整数,即该共享内存段的标识码;失败返回-1
IPC_CREAT、IPC_EXCL本质是宏,用二进制标志位的方式来表示选项。
需要创建共享内存的进程用IPC_CREAT | IPC_EXCL | 0600,后续要和该进程通信的进程使用IPC_CREATE【类似于父进程来创建匿名/命名管道,子进程直接用】。0600表示权限,可以看到perms会随之变化,若perms为0,挂接会失败。
**共享内存的大小一般要取页表大小(4096字节)的整数倍。**建议为4KB的整数倍,因为系统分配共享内存是以4KB为单位的!4KB也是划分内存块的基本单位。
shmat()函数 进程和共享内存挂接
at-attach
功能:将共享内存段连接到进程地址空间
原型void *shmat(int shmid, const void *shmaddr, int shmflg);
参数shmid: 共享内存标识shmaddr:指定连接的地址==NULL:核心自动选择一个地址!=NULL且shmflg!=SHM_RND:以shmaddr为链接地址!=NULL且shmflg==SHM_RND:连接的地址会自动向下调整为SHMLBA的整数倍。公式:shmaddr-(shmaddr % SHMLBA)shmflg==SHM_RDONLY:连接操作用来只读共享内存shmflg:它的两个可能取值是SHM_RND和SHM_RDONLY
返回值成功返回一个指针,指向共享内存第一个节;失败返回-1//假设void* ret为返回值,则判断条件为(long long)ret == -1L[强转为int的前提条件:系统为32为系统!但是linux是64位系统,指针是8个字节,而int是4字节,编译会报错]
理解key使共享内存具有唯一性,以及key和shmid间的关系和区别
ftok()函数返回值是key和shmget()函数返回值是shmid。
首先,共享内存=物理内存块+共享内存相关属性(即操作系统为管理共享内存建立的一个结构体)。
创建共享内存的时候如何保证共享内存在系统中的唯一性?通过key来实现,key类似于fd,通过shmge()t函数将key设置为struct shm{ key_t k; }k上,当共享内存属性的k一样时,就能进入同一块内核内存空间。
区别:shmid类似于fd,供用户使用,key类似于inode,用于标定系统的共享内存,是内核级的描述符;即key是系统层面用的,shmid是给用户用的,是为了解耦,fd和inode同理。
注意:成功挂接后,通过ipcs -m命令查看该块共享内存的属性,可以看到nattch的数字会++.
shmdt()函数 去关联
dt–detach
#include <sys/types.h>
#include <sys/shm.h>
功能:将共享内存段与当前进程脱离
原型int shmdt(const void *shmaddr);
参数shmaddr: 由shmat所返回的指针
返回值成功返回0;失败返回-1
注意:将共享内存段与当前进程脱离不等于删除共享内存段
shmctl()函数 删除共享内存段/查看共享内存属性
#include <sys/ipc.h>
#include <sys/shm.h>功能:用于控制共享内存
原型int shmctl(int shmid, int cmd, struct shmid_ds *buf);
参数shmid:由shmget返回的共享内存标识码cmd:将要采取的动作(有三个可取值)IPC_STAT:把shmid_ds结构中的数据设置为共享内存的当前关联值IPC_ET:在进程有足够权限的前提下,把共享内存的当前关联值设置为shmid_ds数据结构中给出的值IPC_RMID:删除共享内存段buf:指向一个保存着共享内存的模式状态和访问权限的数据结构//当cmd为IPC_RMID时,传NULL;当使用其他cmd时,传一个struct shmid_ds{}数据结构的指针进去,就能获得共享内存的信息(所有者、权限、大小、创建时间等信息)
返回值成功返回0;失败返回-1
注意:有进程和该块共享内存挂接时,即nattch!=0,也可以完成删除操作,但是最好是先将进程去关联后再删除该块共享内存。
linux下是64位平台,无法把指针强转为int类型–8自己无法转4字节,可以把指针转成long long类型,并且给-1加上L
------ Shared Memory Segments --------
key shmid owner perms bytes nattch status
0x66010309 3 yyq 600 4096 0 ------ Shared Memory Segments --------
key shmid owner perms bytes nattch status
0x66010309 3 yyq 600 4096 1 //server先挂接上------ Shared Memory Segments --------
key shmid owner perms bytes nattch status
0x66010309 3 yyq 600 4096 2 //server和client都挂接上了------ Shared Memory Segments --------
key shmid owner perms bytes nattch status
0x66010309 3 yyq 600 4096 1 //client先去关联------ Shared Memory Segments --------
key shmid owner perms bytes nattch status
0x66010309 3 yyq 600 4096 0 //server回收资源
共享内存的数据结构如下
struct shmid_ds {struct ipc_perm shm_perm; /* Ownership and permissions */ //centos用的名称是shm_permsize_t shm_segsz; /* Size of segment (bytes) */time_t shm_atime; /* Last attach time */time_t shm_dtime; /* Last detach time */time_t shm_ctime; /* Last change time */pid_t shm_cpid; /* PID of creator */pid_t shm_lpid; /* PID of last shmat(2)/shmdt(2) */shmatt_t shm_nattch; /* No. of current attaches */...};
struct ipc_perm { // struct shm_permkey_t __key; /* Key supplied to shmget(2) */uid_t uid; /* Effective UID of owner */gid_t gid; /* Effective GID of owner */uid_t cuid; /* Effective UID of creator */gid_t cgid; /* Effective GID of creator */unsigned short mode; /* Permissions + SHM_DEST andSHM_LOCKED flags */unsigned short __seq; /* Sequence number */};
查看共享内存属性
struct shmid_ds ds;
shmctl(shmid, IPC_STAT, &ds);
printf("%d-nattach:%d-key:%d\n", ds.shm_segsz, ds.shm_nattch, ds.shm_perm._key);
通信模块
用到的函数为
int snprintf(char *str, size_t size, const char *format, ...);
向特定的区域做格式化输入,共享内存没有输入输出接口,第一种方法:和以前一样定义一个缓冲区,然后把缓冲区的memcpy过去即可;第二种方法:共享内存和进程挂接上以后,shmat函数会直接给我们返回该段共享内存映射到进程地址空间的void*指针,直接把它强转为char*即可使用。
//方式1
const char* msg = "hello server, I'm client";
pid_t pid = getpid();
int count = 1;
char buffer[1024];
snprintf(buffer,sizeof(buffer), "%s[pid:%d][消息编号:%d]", msg, pid, count);
memcpy(start, buffer, strlen(buffer) + 1);
//方式2--挂接成功的返回值可以强转为char*,字符数组就可以直接用,不用缓冲区
const char* msg = "hello server, I'm client";
pid_t pid = getpid();
int count = 1;
snprintf(start, SHM_SIZE, "%s[pid:%d][消息编号:%d]", msg, pid, count++);
总结
共享内存段的优点
所有进程间通信方式中最快的一个方式,有效减少拷贝次数。==>不用缓冲区和memcpy
共享内存段的缺点
发消息的慢5s,读消息的快1s:读消息会一直读上一条的,等发过来了再读新的。即共享内存不会进行同步和互斥操作,没有对数据进行任何保护。类比管道,写端不写,读端就会阻塞等待;读端不读,写端写到缓冲区满了就不写了。需要使用信号量来对数据进行保护。
面试题:管道和共享内存
比较一下管道和共享内存(场景包括键盘输入和显示器输出),同样的代码,如果用管道/共享内存来实现,需要经过几次拷贝?
- 管道:4次+2次
- 共享内存:2次+2次

优化:共享内存的数据保护
需要实现类似于管道的功能,client写完了再通知server,进行读取,如果client没有写入或者没通知,server就不读取。
思路:同时使用匿名管道和共享内存,用匿名管道进行通知,共享内存传递消息。
相关文章:
systemV共享内存
systemV共享内存 共享内存区是最快的IPC形式。共享内存的大小一般是4KB的整数倍,因为系统分配共享内存是以4KB为单位的(Page)!4KB也是划分内存块的基本单位。 之前学的管道,是通过文件系统来实现让不同的进程看到同一…...
Python基础之if逻辑判断
在学习if语句之前,我们先学习一种数据类型,布尔类型(bool),在if语句中,我们需要通过判断条件是否为真或者假,才进入下面的语句块执行。 一、布尔类型(bool) 布尔类型&a…...
实现pdf文件预览
前言 工作上接到的一个任务,实现pdf的在线预览,其实uniapp中已经有对应的api:uni.openDocument(OBJECT)(新开页面打开文档,支持格式:doc, xls, ppt, pdf, docx, xlsx, pptx。)**实现了相关功能…...
【java】alibaba Fastjson --全解史上最快的JSON解析库
文章目录前序Fastjson 简介Fastjson 的优点速度快使用广泛测试完备使用简单功能完备下载和使用将 Java 对象转换为 JSON 格式JSONField创建 JSON 对象JSON 字符串转换为 Java 对象使用 ContextValueFilter 配置 JSON 转换使用 NameFilter 和 SerializeConfigFastjson 处理日期F…...
绝对零基础的C语言科班作业(期末模拟考试)(十道编程题)
编程题(共10题; 共100.0分)(给猛男妙妙屋更一篇模拟考试)模拟1(输出m到n的素数)从键盘输入两个整数[m,n], 输出m和n之间的所有素数。 输入样例:3,20输出样例:…...
按位与为零的三元组[掩码+异或的作用]
掩码异或的作用前言一、按位与为零的三元组二、统计分组1、map统计分组2、异或掩码总结参考资料前言 当a b 0时,我们能够很清楚的知道b是个什么值,b 0 - a -a,如果当a & b 0时,我们能够很清楚的知道b是什么值吗…...
C++基础篇(一)-- 简单入门
C 语言是在优化 C 语言的基础上为支持面向对象的程序设计而研制的一个通用目的的程序设计语言。在后来的持续研究中,C 增加了许多新概念,例如虚函数、重载、继承、标准模板库、异常处理、命名空间等。 C 语言的特点主要表现在两个方面:全面兼…...
前端整理 —— javascript 2
1. generator(生成器) 详细介绍 generator 介绍 generator 是 ES6 提供的一种异步编程解决方案,在语法上,可以把它理解为一个状态机,内部封装了多种状态。执行generator,会生成返回一个遍历器对象。返回的…...
Spring-注解注入
一、回顾XML注解 bean 配置 创建 bean public class Student { } 配置 xml bean <?xml version"1.0" encoding"UTF-8"?> <beans xmlns"http://www.springframework.org/schema/beans"xmlns:xsi"http://www.w3.org/2001/XMLSche…...
华为校招机试 - 攻城战(Java JS Python)
目录 题目描述 输入描述 输出描述 用例 题目解析 JavaScript算法源码 Java算法源码...
Docker入门
Docker一、何为DockerDocker是一个开源的应用容器引擎,基于GO语言并遵循从Apache2.0协议开源。Docker可以让开发者打包他们的应用以及依赖包到一个轻量级、可移植的容器中,然后在发布到任何流行的Linux机器上,也可以实现虚拟化。容器是完全使…...
时间序列分析 | CNN-LSTM卷积长短期记忆神经网络时间序列预测(Matlab完整程序)
时间序列分析 | CNN-LSTM卷积长短期记忆神经网络时间序列预测(Matlab完整程序) 目录 时间序列分析 | CNN-LSTM卷积长短期记忆神经网络时间序列预测(Matlab完整程序)预测结果模型输出基本介绍完整程序参考资料预测结果 模型输出 layers = 具有以下层的 151 Layer 数组:...
【蒸滴C】C语言结构体入门?看这一篇就够了
目录 一、结构体的定义 二、结构的声明 例子 三、 结构成员的类型 结构体变量的定义和初始化 1.声明类型的同时定义变量p1 2.直接定义结构体变量p2 3.初始化:定义变量的同时赋初值。 4.结构体变量的定义放在结构体的声明之后 5.结构体嵌套初始化 6.结构体…...
第十三届蓝桥杯
这里写目录标题一、刷题统计(ceil函数返回的是等值于某最小整数的浮点值,不强制转换回int就wa,没错就连和int整数相加都wa二、修剪灌木(主要应看清楚会调转方向三、统计子矩阵(前缀和滑动窗口⭐)四、[积木画…...
消息队列mq
应用场景: 1、解耦 2、削峰填谷 3、异步处理 4、消息通讯 工作模式: 一个消息只能被消费一次(订阅模式除外),消费者接受到消息会回调业务逻辑,消费逻辑写在回调函数里面。 1、简单模式:一个生产…...
[学习笔记]黑马程序员Spark全套视频教程,4天spark3.2快速入门到精通,基于Python语言的spark教程
文章目录视频资料:一、Spark基础入门(环境搭建、入门概念)第二章:Spark环境搭建-Local2.1 课程服务器环境2.2 Local模式基本原理2.3 安装包下载2.4 Spark Local模式部署第三章:Spark环境搭建-StandAlone3.1 StandAlone…...
git push和 git pull的使用
git push与git pull是一对推送/拉取分支的git命令。git push 使用本地的对应分支来更新对应的远程分支。$ git push <远程主机名> <本地分支名>:<远程分支名>*注意: 命令中的本地分支是指将要被推送到远端的分支,而远程分支是指推送的目标分支&am…...
首发,pm3包,一个用于多组(3组)倾向评分匹配的R包
目前,本人写的第二个R包pm3包已经正式在CRAN上线,用于3组倾向评分匹配,只能3组不能多也不能少。 可以使用以下代码安装 install.packages("pm3")什么是倾向性评分匹配?倾向评分匹配(Propensity Score Match…...
基于Canal的数据同步
基于Canal的数据同步 一、 系统结构 该数据同步系统由Spring Boot和Canal共同组成。 Spring Boot 是一个流行的 Java Web 框架,而 Canal 则是阿里巴巴开源的 MySQL 数据库的数据变更监听框架。结合 Spring Boot 和 Canal,可以实现 MySQL 数据库的实时数…...
vuetify设置页面默认主题色
前言 最近工作中接到一个任务: 项目中分light和dark两种主题色a、b页面默认为dark其他页面默认为light 项目前端环境: vue2jsyarnvuexvuetifyelement ui 解决思路 routerjs中配置路径时进行默认主题设置 在左侧aside点击菜单时,进行主题切…...
KubeSphere 容器平台高可用:环境搭建与可视化操作指南
Linux_k8s篇 欢迎来到Linux的世界,看笔记好好学多敲多打,每个人都是大神! 题目:KubeSphere 容器平台高可用:环境搭建与可视化操作指南 版本号: 1.0,0 作者: 老王要学习 日期: 2025.06.05 适用环境: Ubuntu22 文档说…...
Flask RESTful 示例
目录 1. 环境准备2. 安装依赖3. 修改main.py4. 运行应用5. API使用示例获取所有任务获取单个任务创建新任务更新任务删除任务 中文乱码问题: 下面创建一个简单的Flask RESTful API示例。首先,我们需要创建环境,安装必要的依赖,然后…...
Java 语言特性(面试系列1)
一、面向对象编程 1. 封装(Encapsulation) 定义:将数据(属性)和操作数据的方法绑定在一起,通过访问控制符(private、protected、public)隐藏内部实现细节。示例: public …...
MFC内存泄露
1、泄露代码示例 void X::SetApplicationBtn() {CMFCRibbonApplicationButton* pBtn GetApplicationButton();// 获取 Ribbon Bar 指针// 创建自定义按钮CCustomRibbonAppButton* pCustomButton new CCustomRibbonAppButton();pCustomButton->SetImage(IDB_BITMAP_Jdp26)…...
五年级数学知识边界总结思考-下册
目录 一、背景二、过程1.观察物体小学五年级下册“观察物体”知识点详解:由来、作用与意义**一、知识点核心内容****二、知识点的由来:从生活实践到数学抽象****三、知识的作用:解决实际问题的工具****四、学习的意义:培养核心素养…...
Keil 中设置 STM32 Flash 和 RAM 地址详解
文章目录 Keil 中设置 STM32 Flash 和 RAM 地址详解一、Flash 和 RAM 配置界面(Target 选项卡)1. IROM1(用于配置 Flash)2. IRAM1(用于配置 RAM)二、链接器设置界面(Linker 选项卡)1. 勾选“Use Memory Layout from Target Dialog”2. 查看链接器参数(如果没有勾选上面…...
Web 架构之 CDN 加速原理与落地实践
文章目录 一、思维导图二、正文内容(一)CDN 基础概念1. 定义2. 组成部分 (二)CDN 加速原理1. 请求路由2. 内容缓存3. 内容更新 (三)CDN 落地实践1. 选择 CDN 服务商2. 配置 CDN3. 集成到 Web 架构 …...
Redis的发布订阅模式与专业的 MQ(如 Kafka, RabbitMQ)相比,优缺点是什么?适用于哪些场景?
Redis 的发布订阅(Pub/Sub)模式与专业的 MQ(Message Queue)如 Kafka、RabbitMQ 进行比较,核心的权衡点在于:简单与速度 vs. 可靠与功能。 下面我们详细展开对比。 Redis Pub/Sub 的核心特点 它是一个发后…...
Java编程之桥接模式
定义 桥接模式(Bridge Pattern)属于结构型设计模式,它的核心意图是将抽象部分与实现部分分离,使它们可以独立地变化。这种模式通过组合关系来替代继承关系,从而降低了抽象和实现这两个可变维度之间的耦合度。 用例子…...
Golang——7、包与接口详解
包与接口详解 1、Golang包详解1.1、Golang中包的定义和介绍1.2、Golang包管理工具go mod1.3、Golang中自定义包1.4、Golang中使用第三包1.5、init函数 2、接口详解2.1、接口的定义2.2、空接口2.3、类型断言2.4、结构体值接收者和指针接收者实现接口的区别2.5、一个结构体实现多…...
