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.共享内存

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Vue项目的搭建

Node.js 下载 Node.js — Download (nodejs.org)https://nodejs.org/en/download/ 安装 测试 winR->cmd执行 node -v配置 在安装目录下创建两个子文件夹node_cache和node_global,我的就是 D:\nodejs\node_cache D:\nodejs\node_global 在node_global文件下再创建一个…

【SQL】1174. 即时食物配送 II (窗口函数row_number; group by写法;对比;定位错因)

前述 推荐学习&#xff1a; 通俗易懂的学会&#xff1a;SQL窗口函数 题目描述 leetcode题目&#xff1a;1174. 即时食物配送 II 写法一&#xff1a;窗口函数 分组排序&#xff08;以customer_id 分组&#xff0c;按照order_date 排序&#xff09;&#xff0c;窗口函数应用。…

kubernetes-有状态和无状态服务

kubernetes-有状态和无状态服务 kubernetes-有状态和无状态服务1.有状态的应用1.1、理解1.2、特点 2、无状态应用2.1、理解2.2、特点 3、玩一下3.1、启动一个nginx无状态的业务3.2、启动一个nginx有状态的业务 4、无头服务4.1、无头服务的特点&#xff1a;4.2、无头服务的用途&…

力扣每日一题 最小高度树 BFS 双向

Problem: 310. 最小高度树 思路 &#x1f468;‍&#x1f3eb; 参考地址 复杂度 时间复杂度: O ( n ) O(n) O(n) 空间复杂度: O ( n ) O(n) O(n) Code import java.util.ArrayList; import java.util.LinkedList; import java.util.List; import java.util.Queue;publ…

企业数据流动安全管理软件(深度解析文章)

企业数据重要性不言而喻&#xff0c;而同时数据的流动和共享也带来了安全风险&#xff0c;如何确保企业数据在流动过程中的安全性&#xff0c;也成为了企业需要面临的重要问题。 企业数据流动安全管理软件的主要功能是监控和管理企业数据的流动过程。 它能够对企业内部的数据…

Ps:直接选择工具

直接选择工具 Direct Selection Tool可用于选择和调整路径或形状中的锚点和路径线段。 快捷键&#xff1a;A 直接选择工具的指针形状为白箭头。当需要调整锚点、方向调杆、路径线段以及对选中的多个锚点子路径进行移动、变换&#xff08;缩放、旋转、扭曲、斜切、变形等&#x…

蓝桥杯刷题(十)

1.翻转 代码 输入数据&#xff0c;每组数据进行比较&#xff0c;j的范围掐头去尾&#xff0c;若a[j]b[j]&#xff0c;继续&#xff0c;若出现010,101子串则改成000,111&#xff0c;遍历完后比较a是否等于b&#xff0c;相同则输出次数&#xff0c;不同则输出-1。 for _ in ran…

智慧城市新篇章:数字孪生的力量与未来

随着信息技术的迅猛发展和数字化浪潮的推进&#xff0c;智慧城市作为现代城市发展的新模式&#xff0c;正在逐步改变我们的生活方式和社会结构。在智慧城市的构建中&#xff0c;数字孪生技术以其独特的优势&#xff0c;为城市的规划、管理、服务等方面带来了革命性的变革。本文…

目标检测---IOU计算详细解读(IoU、GIoU、DIoU、CIoU、EIOU、Focal-EIOU、WIOU)

常见IoU解读与代码实现 一、✒️IoU&#xff08;Intersection over Union&#xff09;1.1 &#x1f525;IoU原理☀️ 优点⚡️缺点 1.2 &#x1f525;IoU计算1.3 &#x1f4cc;IoU代码实现 二、✒️GIoU&#xff08;Generalized IoU&#xff09;2.1 GIoU原理☀️优点⚡️缺点 2…

【Spark编程基础】RDD 编程初级实践(附源代码)

目录 一、实验目的二、实验平台三、实验内容1.spark-shell 交互式编程2.编写独立应用程序实现数据去重3.编写独立应用程序实现求平均值问题 一、实验目的 1、熟悉 Spark 的 RDD 基本操作及键值对操作&#xff1b; 2、熟悉使用 RDD 编程解决实际具体问题的方法 二、实验平台 …

百科源码生活资讯百科门户类网站百科知识,生活常识

百科源码生活资讯百科门户类网站百科知识,生活常识 百科源码安装环境 支持php5.6&#xff0c;数据库mysql即可&#xff0c;需要有子目录权限&#xff0c;没有权限的话无法安装 百科源码可以创建百科内容&#xff0c;创建活动内容。 包含用户注册&#xff0c;词条创建&#xff…

VScode(8)之阅读大型CC++工程

VScode(8)之阅读大型CC工程(Linux内核)代码 Author&#xff1a;Once Day Date&#xff1a;2023年4月25日/2024年3月17日 漫漫长路&#xff0c;有人对你微笑过嘛… 全系列文章请查看专栏: VScode开发_Once-Day的博客-CSDN博客 参考文档: 1. 历史包袱 由于上世纪70-80年代的…

综合知识篇08-数据库系统考点(2024年软考高级系统架构设计师冲刺知识点总结系列文章)

专栏系列文章: 2024高级系统架构设计师备考资料(高频考点&真题&经验)https://blog.csdn.net/seeker1994/category_12593400.html案例分析篇00-【历年案例分析真题考点汇总】与【专栏文章案例分析高频考点目录】(2024年软考高级系统架构设计师冲刺知识点总结-案例…

Ubuntu 16.04 设置 root 密码

Ubuntu 16.04 设置 root 密码 1. sudo2. parserReferences 1. sudo sudo (/ˈsuːduː/ or /ˈsuːdoʊ/) is a program for Unix-like computer operating systems that allows users to run programs with the security privileges of another user, by default the superus…

【系统性】 循序渐进学C++

循序渐进学C 第一阶段&#xff1a;基础 一、环境配置 1.1.第一个程序&#xff08;基本格式&#xff09; ​ #include <iosteam> using namespace std;int main(){cout<<"hello world"<<endl;system("pause"); }​ 模板 #include &…

论文阅读——RSGPT

RSGPT: A Remote Sensing Vision Language Model and Benchmark 贡献&#xff1a;构建了一个高质量的遥感图像描述数据集&#xff08;RSICap&#xff09;和一个名为RSIEval的基准评估数据集&#xff0c;并在新创建的RSICap数据集上开发了基于微调InstructBLIP的遥感生成预训练…

ElasticSearch架构设计

一、基础概念 Elasticsearch 是一个分布式可扩展的实时搜索和分析引擎,一个建立在全文搜索引擎 Apache Lucene™ 基础上的搜索引擎.当然 Elasticsearch 并不仅仅是 Lucene 那么简单&#xff0c;它不仅包括了全文搜索功能&#xff0c;还可以进行以下工作: 一个分布式的实时文档…

AI基础知识(2)--决策树,神经网络

1.什么是决策树&#xff1f; 决策树是一类常见的机器学习方法&#xff0c;决策树是基于树的结构来进行决策。决策过程中提出的每一个问题都是对于属性的“测试”&#xff0c;决策的最终结论对应了我们希望的判定结果。一个决策树包含一个根节点&#xff0c;若干个内部节点和若…

MyBatisPlus——Wrapper

Wrapper体系 QueryWrapper 使用字符串表示列名&#xff0c;通过字符串拼接的方式构建查询条件 再将 wrapper 作为条件参数&#xff0c;写入BaseMapper提供的查找方法中&#xff08;或其他数据库方法&#xff09; QueryWrapper<QueryEntity> wrapper new QueryWrapper&l…

Python笔记|字符串合并、切片、索引

一、合并 字符串可以用 合并&#xff08;粘到一起&#xff09;&#xff0c;也可以用 * 重复&#xff1a; >>> 3 * un ium unununium 相邻的两个或多个字符串字面值&#xff08;引号标注的字符&#xff09;会自动合并&#xff1a; >>> Py thon Python …