06.共享内存

1.内存映射(mmap)

我们在单片机中首先接触到了映射的概念

将一个寄存器的地址映射到了另外的一个存储空间中

内存映射:

内存映射(Memory Mapping)是一种在计算机科学中使用的技术,它允许将文件或其他设备的内容映射到进程的地址空间中,使得进程可以像访问内存一样访问这些内容内存映射可以提供一种方便的方式来处理大文件或设备的数据,同时也可以加速数据的读取和写入操作。

在内存映射中,操作系统会将文件的内容映射到进程的虚拟内存地址空间中的一个或多个页面(page),从而使得进程可以通过读写内存地址来访问文件的内容,而无需使用传统的文件I/O操作

使用内存映射的优点包括: 

  • 简化文件或设备的访问:通过内存映射,文件或设备的内容可以直接映射到内存中,使得进程可以像访问内存一样访问文件或设备的内容,而无需手动进行文件I/O操作(read write底层(硬件层次,操作相关的设备))。
  • 提高性能:由于内存映射是通过文件系统缓存实现的,读取文件时可以直接从内存中获取数据,而避免了磁盘I/O操作,因此可以提高读取性能。
  • 易于共享数据:多个进程可以将同一个文件映射到各自的地址空间中,从而实现共享数据。

需要注意的是,使用内存映射时需要谨慎处理内存访问越界和同步的问题,以避免出现内存错误或数据不一致的情况。此外,内存映射对于处理大文件或设备的数据非常有用,但在某些情况下可能不适用于小文件或频繁更新的数据

直接采用共享内存的方式进行数据传输,可以不经过内核态,读写速度块。

映射对应关系:

内存映射部分相关函数:

建立映射区:mmap()函数
头文件:
#include  <sys/mman.h>
void *mmap(void *addr, size_t length, int prot, int flags,int fd, off_t offset);
参数:
addr 地址, 填 NULL(映射区域的起始地址)--让系统帮你确定地址
length 长度 要申请的映射区的长度(字节)rt-thread中创建任务开辟的空间,按字的大小去开辟prot 权限
PROT_READ 可读
PROT_WRITE 可写
flags 标志位
MAP_SHARED 共享的 -- 对映射区的修改会影响源文件
MAP_PRIVATE 私有的
fd 文件描述符 需要打开一个文件
offset 指定一个偏移位置 , 从该位置开始映射--0
返回值
成功 返回映射区的首地址
失败 返回 MAP_FAILED ((void *) -1)
释放映射区:
int munmap(void *addr, size_t length);
addr 映射区的首地址
length 映射区的长度
扩展文件大小:
int truncate(const char *path, off_t length);
path 要拓展的文件
length 要拓展的长度

释放映射区域:

int munmap(void *addr, size_t length);
addr 映射区的首地址
length 映射区的长度
返回值
成功 返回 0
失败 返回 -1

1.磁盘空间---open函数新建一个文件

2.确定映射关系--mmap

3.确定文件大小--truncate

4.对映射区域进行写操作 ----

buf[128]="qqqdfsadfa......."

读操作:

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <string.h>#include <sys/stat.h>
#include <fcntl.h>
//进程间的通信--队列中使用的头文件
#include <sys/ipc.h>
#include <sys/msg.h>
#include  <sys/mman.h>int main(void)
{//char buf[256];int fd= open("map_file",O_RDWR|O_CREAT,0777);printf("fd-->%d\n",fd);//    //int truncate(const char *path, off_t length);
//     truncate("map_file",64);//void *mmap(void *addr, size_t length, int prot, int flags,int fd, off_t offset);char* buf=(char *) mmap(NULL,8,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);if(buf==((char *)-1)){perror("mmap:");exit(-1);}printf("buff-->%s\n",buf);// strcpy(buf,"hello world");return 0;
}

写操作:

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <string.h>#include <sys/stat.h>
#include <fcntl.h>
//进程间的通信--队列中使用的头文件
#include <sys/ipc.h>
#include <sys/msg.h>
#include  <sys/mman.h>int main(void)
{// char buf[256];int fd= open("map_file",O_RDWR|O_CREAT,0777);printf("fd-->%d\n",fd);//void *mmap(void *addr, size_t length, int prot, int flags,int fd, off_t offset);char *buf=(char *) mmap(NULL,8,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);if(buf==(char *)-1){perror("mmap:");exit(-1);}//int truncate(const char *path, off_t length);truncate("map_file",8);strcpy(buf,"hello world");return 0;
}

2.共享内存

共享内存允许两个或者多个进程共享给定的存储区域。

共享内存和内存映射一样吗??

共享内存和内存映射都可以用于进程间的通信,但是内存映射主要是用于文件之间数据传输(相对于共享内存来说,速度更快)

内存映射相当于,在磁盘上开辟了空间,然后将需要用到的数据全部临时提取到内存中去运行处理,处理完成之后,后续在保存至物理磁盘中

共享内存是进程间的通信使用的最多的通信方式,用于传输数据量比较大的情景

共享内存是通过进程本身新建物理内存,然后,其他的进程只要是可以获取共享内存的描述符,即可访问存储空间

和物理存储相对应的还有虚拟内存

共享内存的特点

1、 共享内存是进程间共享数据的一种最快的方法。 一个进程向共享的内存区域写入了数据, 共享这个内存区域的所有进程就可以立刻看到其中的内容。

2、 使用共享内存要注意的是多个进程之间对一个给定存储区访问的互斥。 若一个进程正在向共享内存区写数据, 则在它做完这一步操作前, 别的进程不应当去读、 写这些数据。

互斥量:特殊信号量,只有0和1,代表对临界资源的访问,线程对于互斥资源的访问,是独占式享用,如果其他的线程需要访问互斥量,那么需要等待资源被释放,否则就访问不了。

互斥量可以有效地降低优先级反转带来的危害,如何解决的???

共享内存中没有互斥和同步的机制,需要结合信号量来使用        

在 ubuntu 部分版本中共享内存限制值如下 共享存储区的最小字节数:

1 共享存储区的最大字节数: 32M

共享存储区的最大个数: 4096

每个进程最多能映射的共享存储区的个数: 4096

相关API函数:

获取标识符--shmget()

#include <sys/ipc.h>
#include <sys/shm.h>
int shmget(key_t key, size_t size,int shmflg);
功能:创建或打开一块共享内存区
参数:
key: IPC 键值
size: 该共享存储段的长度(字节)
shmflg: 标识函数的行为及共享内存的权限。
参数:
shmflg:
IPC_CREAT: 如果不存在就创建
IPC_EXCL: 如果已经存在则返回失败
位或权限位: 共享内存位或权限位后可以设置共享内存的访问权限, 格式
和 open 函数的 mode_t 一样, 但可执行权限未使用。返回值:
成功: 返回共享内存标识符。
失败: 返回-1。

查看共享内存:

使用 shell 命令操作共享内存查看共享内存 
ipcs -m --内存
ipcs -q --队列
删除共享内存 
ipcrm -m  shmid  --删除shmid的共享内存
ipcs -lm  查看当前系统的共享内存空间大小

共享区映射--shmat()

#include <sys/types.h>
#include <sys/shm.h>
void *shmat(int shmid, const void *shmaddr,int shmflg);
功能:
将一个共享内存段映射到调用进程的数据段中。
参数:
shmid: 共享内存标识符。
shmaddr: 共享内存映射地址(若为 NULL 则由系 统自动指
定), 推荐使用 NULL。
shmflg: 共享内存段的访问权限和映射条件
0: 共享内存具有可读可写权限。
SHM_RDONLY: 只读。
SHM_RND: (shmaddr 非空时才有效)
没有指定 SHM_RND 则此段连接到 shmaddr 所指定的地址上(shmaddr 必需
页对齐)。
指定了 SHM_RND 则此段连接到 shmaddr- shmaddr%SHMLBA 所表示的地址
上。
返回值:
成功: 返回共享内存段映射地址
失败: 返回 -1注意:shmat 函数使用的时候第二个和第三个参数一般设为 NULL 和 0,
即系统自动指定共享内存地址, 并且共享内存可读可写。

解除共享映射区:

#include <sys/types.h>
#include <sys/shm.h>
int shmdt(const void *shmaddr);
功能:
将共享内存和当前进程分离(仅仅是断开联系并不删除共享内存)。
参数:
shmaddr: 共享内存映射地址。
返回值:
成功返回 0, 失败-1

共享内存的控制:

#include <sys/ipc.h>
#include <sys/shm.h>
int shmctl(int shmid, int cmd,struct shmid_ds *buf);
功能: 共享内存空间的控制。
参数:
shmid: 共享内存标识符。
cmd: 函数功能的控制。
buf: shmid_ds 数据类型的地址, 用来存放或修改共享内存的属性。
cmd: 函数功能的控制
IPC_RMID: 删除。
IPC_SET: 设置 shmid_ds 参数。
IPC_STAT: 保存 shmid_ds 参数。
SHM_LOCK: 锁定共享内存段(超级用户)。
SHM_UNLOCK: 解锁共享内存段。
返回值:
成功返回 0, 失败返回 -1。
注意: SHM_LOCK 用于锁定内存, 禁止内存交换。 并不代表共享内存被锁定后禁
止其它进程访问。 其真正的意义是: 被锁定的内存不允许被交换到虚拟内存中。这
样做的优势在于让共享内存一直处于内存中, 从而提高程序性能

读操作:

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <string.h>#include <sys/stat.h>
#include <fcntl.h>
//进程间的通信--队列中使用的头文件
#include <sys/ipc.h>
#include <sys/msg.h>
#include  <sys/mman.h>#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/msg.h>
//按字节寻址
int main(void)
{
//     // char buf[256];
//    int fd= open("map_file",O_RDWR|O_CREAT,0777);
//     printf("fd-->%d\n",fd);//    //void *mmap(void *addr, size_t length, int prot, int flags,int fd, off_t offset);
//     char *buf=(char *) mmap(NULL,8,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);
//     if(buf==(char *)-1)
//     {
//         perror("mmap:");
//         exit(-1);
//     }
//     //int truncate(const char *path, off_t length);
//     truncate("map_file",8);//     strcpy(buf,"hello world");key_t key =ftok("./",3);//获取共享内存的描述符
//int shmget(key_t key, size_t size,int shmflg);int shm_id = shmget(key,32,IPC_CREAT|0666);//获取共享内存的地址// void *shmat(int shmid, const void *shmaddr,int shmflg);char *buf=(char *)shmat(shm_id,NULL,0);//   strcpy(buf,"zz2302 hello");
//    读数据printf("buf-->%s\n",buf);memset(buf,0,32);//int shmdt(const void *shmaddr);return 0;
}

写操作:

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <string.h>#include <sys/stat.h>
#include <fcntl.h>
//进程间的通信--队列中使用的头文件
#include <sys/ipc.h>
#include <sys/msg.h>
#include  <sys/mman.h>#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/msg.h>
//按字节寻址
int main(void)
{
//     // char buf[256];
//    int fd= open("map_file",O_RDWR|O_CREAT,0777);
//     printf("fd-->%d\n",fd);//    //void *mmap(void *addr, size_t length, int prot, int flags,int fd, off_t offset);
//     char *buf=(char *) mmap(NULL,8,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);
//     if(buf==(char *)-1)
//     {
//         perror("mmap:");
//         exit(-1);
//     }
//     //int truncate(const char *path, off_t length);
//     truncate("map_file",8);//     strcpy(buf,"hello world");key_t key =ftok("./",3);//获取共享内存的描述符
//int shmget(key_t key, size_t size,int shmflg);int shm_id = shmget(key,32,IPC_CREAT|0666);//获取共享内存的地址// void *shmat(int shmid, const void *shmaddr,int shmflg);char *buf=(char *)shmat(shm_id,NULL,0);strcpy(buf,"zz2302 hello");
//int shmdt(const void *shmaddr);return 0;
}

进程间的通信方式:

1.信号

2.管道

3.消息队列

4.共享内存

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

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

相关文章

idea warning:java源值已过时将在未来所有发行版中删除

在idea中运行maven项目 如果出现idea warning:java源值已过时将在未来所有发行版中删除&#xff0c;详见如下截图所示&#xff1a; 注意&#xff1a;jdk8 要解决这个警告需要设置3个地方 首先打开File->Project Structure中的Project&#xff0c;将SDK和language level都设…

五、保持长期高效的七个法则(二)Rules for Staying Productive Long-Term(1)

For instance - lets say youre a writer.You have a bunch of tasks on your plate for the day, but all of a sudden you get a really good idea for an essay. You should probably start writing now or youll lose your train of thought.What should you do? 举例来说…

分布式搜索引擎(3)

1.数据聚合 **[聚合&#xff08;](https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations.html)[aggregations](https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations.html)[&#xff09;](https://www.ela…

机器学习(26)回顾gan+文献阅读

文章目录 摘要Abstract一、李宏毅机器学习——GAN1. Introduce1.1 Network as Generator1.2 Why distribution 2. Generative Adversarial Network2.1 Unconditional generation2.2 Basic idea of GAN 二、文献阅读1. 题目2. abstract3. 网络架构3.1 Theoretical Results 4. 文…

Oracle P6 Professional 配置连接数据库总结

前言 P6 Professional作为Oracle P6计划管理系统的重要套件之一&#xff0c;其操作出色&#xff0c;体检佳&#xff0c;是非常多的计划工程师跟踪项目进度计划的辅助工具。自20年前&#xff0c;Professional一直在不断的演变更新&#xff0c;以适应当前的新技术&#xff0c;从…

【MySQL】MySQL事务

文章目录 一、CURD不加控制&#xff0c;会有什么问题&#xff1f;二、事务的概念三、事务出现的原因四、事务的版本支持五、事务提交方式六、事务常见操作方式七、事务隔离级别1.理解隔离性12.隔离级别3.查看与设置隔离性4.读未提交【Read Uncommitted】5.读提交【Read Committ…

【Numpy】练习题100道(76-100题完结)

&#x1f33b;个人主页&#xff1a;相洋同学 &#x1f947;学习在于行动、总结和坚持&#xff0c;共勉&#xff01; #学习笔记# Git-hub链接 题目列表&#xff08;题解往下翻&#xff09; 76.考虑一个一维数组Z&#xff0c;构建一个二维数组&#xff0c;其第一行为(Z[0],Z[…

【鸿蒙HarmonyOS开发笔记】组件编程技巧之使用@Builder装饰器实现UI结构复用

概述 当页面有多个相同的UI结构时&#xff0c;若每个都单独声明&#xff0c;同样会有大量重复的代码。为避免重复代码&#xff0c;可以将相同的UI结构提炼为一个自定义组件&#xff0c;完成UI结构的复用。 除此之外&#xff0c;ArkTS还提供了一种更轻量的UI结构复用机制Build…

小白DB补全计划Day1-LeetCode:SQL基本操作select

前言&#xff1a;找工作&#xff08;主人&#xff09;的任务罢了 链接&#xff1a;1757. 可回收且低脂的产品 - 力扣&#xff08;LeetCode&#xff09; 584. 寻找用户推荐人 - 力扣&#xff08;LeetCode&#xff09; 来源&#xff1a;LeetCode 对DB篇的SQL章不太知道怎么写…

数学建模-估计出租车的总数

文章目录 1、随机抽取的号码在总体的排序 1、随机抽取的号码在总体的排序 10个号码从小到大重新排列 [ x 0 , x ] [x_0, x] [x0​,x] 区间内全部整数值 ~ 总体 x 1 , x 2 , … , x 10 总体的一个样本 x_1, x_2, … , x_{10} ~ 总体的一个样本 x1​,x2​,…,x10​ 总体的一个样…

mysql与redis数据测试

题目要求 1.新建一张user表&#xff0c;在表内插入10000条数据。 2.①通过jdbc查询这10000条数据&#xff0c;记录查询时间。 ②通过redis查询这10000条数据&#xff0c;记录查询时间。 3.再次查询这一万条数据&#xff0c;要求根据年龄进行排序&#xff0c;mysql和redis各实现…

【FPGA/IC】什么是模块化设计?

什么是模块化设计 FPGA/IC设计中根据模块层次的不同有两种基本的设计方法&#xff1a; 自下而上方法对设计进行逐次划分的过程是从基本单元出发的&#xff0c;设计树最末枝上的单元是已经设计好的基本单元&#xff0c;或者其他项目开发好的单元或者IP。该方法先对底层的功能块…

探索发布-订阅模式的深度奥秘-实现高效、解耦的系统通信

​&#x1f308; 个人主页&#xff1a;danci_ &#x1f525; 系列专栏&#xff1a;《设计模式》 &#x1f4aa;&#x1f3fb; 制定明确可量化的目标&#xff0c;坚持默默的做事。 &#x1f680; 转载自&#xff1a;探索设计模式的魅力&#xff1a;探索发布-订阅模式的深度奥秘-…

Jest:JavaScript的单元测试利器

&#x1f90d; 前端开发工程师、技术日更博主、已过CET6 &#x1f368; 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 &#x1f560; 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 &#x1f35a; 蓝桥云课签约作者、上架课程《Vue.js 和 E…

作品展示ETL

1、ETL 作业定义、作业导入、控件拖拽、执行、监控、稽核、告警、报告导出、定时设定 欧洲某国电信系统数据割接作业定义中文页面&#xff08;作业顶层&#xff0c;可切英文&#xff0c;按F1弹当前页面帮助&#xff09; 涉及文件拆分、文件到mysql、库到库、数据清洗、数据转…

Vue mqtt 附在线mqtt客户端地址 + 完整示例

mqtt&#xff1a;轻量级物联网消息推送协议。 目录 一、介绍 1、官方文档 1&#xff09;npm网 2) 中文网 MQTT中文网_MQTT 物联网接入平台-MQTT.CN 2、官方示例 二、准备工作 1、安装依赖包 2、示例版本 三、使用步骤 1、在单页面引入 mqtt 四、完整示例 tips 一、介…

渐开线花键环规的几种加工方法

小伙伴们大家好&#xff0c;今天咱们聊一聊渐开线花键环规的几种加工方法。 渐开线花键环规是在汽车、摩托车以及机械制造工业应用非常广泛的一种检测量具。它属于是一种内花键齿轮&#xff0c;其精度和表面粗糙度要求都比较高。采用的加工方法也比较多&#xff0c;下面详细看…

【爬虫逆向】Python逆向采集猫眼电影票房数据

进行数据抓包&#xff0c;因为这个网站有数据加密 !pip install jsonpathCollecting jsonpathDownloading jsonpath-0.82.2.tar.gz (10 kB)Preparing metadata (setup.py) ... done Building wheels for collected packages: jsonpathBuilding wheel for jsonpath (setup.py) .…

Android VINF

周末搞这玩意欲仙欲死&#xff0c;没办法只有看看。VINTF是供应商接口对象&#xff08;VINTF 对象&#xff09;&#xff0c;准确的说&#xff0c;这个是属于兼容性矩阵概念。。。有点想起了以前看过的一个电影&#xff0c;异次元杀阵。。。下面是谷歌官方的图。 本质上其实就是…

C++之类和对象(3)

目录 1. 再谈构造函数 1.1 构造函数体赋值 1.2 初始化列表 1.3 explicit 2. static成员 2.1 概念 3. 友元 3.1 友元函数 3.2 友元类 4. 内部类 5. 匿名对象 6. 拷贝对象时编译器做出的优化 1. 再谈构造函数 1.1 构造函数体赋值 class Date { public:Date(int year2024…