Linux应用---内存映射

写在前面:

        在进程间通信中,有一种方式内存映射。内存映射也是进程间通信的方式之一,其效率高,可以直接对内存进行操作。本节我们对内存映射进行学习,并结合案例进行实践。

1、基本理论

内存映射:是将磁盘文件中的数据映射到内存,用户通过修改内存就能修改磁盘文件。

那通过内存映射如何实现进程之间的通信呢?简单来说就是将同一个文件存储映射部分分别映射到不同的进程中,两个进程通过改变文件的内容(读写内存)来实现通信,不必再使用read和write函数等系统调用,加快文件的读取和写入。

内存映射相关函数

#include <sys/mman.h>
void *mmap(void *addr, size_t length, int prot, int flags,int fd, off_t offset);//用于文件或者设备映射到内存中去
int munmap(void *addr, size_t length);//释放内存映射

1、mmap函数

涉及头文件:#include <sys/mman.h>

函数原型:void *mmap(void *addr, size_t length, int prot, int flags,int fd, off_t offset);

功能:将一个文件或者设备的数据映射到内存中去;

参数:  - void *adder:NULL;由内核指定。

             -lenth:要映射的内存的长度,这个值不能为0;建议使用文件的长度;

                    获取文件的长度:stat lseek;

                 没有达到分页的大小,按照分页大小进行,所以是分页的整数倍。

                 所以一般情况下,申请的内存区域大于等于文件的大小。

             -prot:对申请的内存区的操作权限;

                     PROT_EXEC  可执行的权限

                     PROT_READ  读的权限

                     PROT_WRITE 写的权限

                     PROT_NONE  没有权限

                  要操作映射内存,必须要读的权限-PROT_READ、PROT_READ|PROT_WRITE

              -flags:

               MAP_SHARED:映射区的数据会自动和磁盘文件进行同步,如果要完成进程间通信,必须设置这个选项;

               MAP_PRIVATE:不同步,内存映射区的数据改变了,对原来的文件不会修改,会重新创建一个新的文件。copy on write.

                -fd:

                    需要操作的文件描述符,通过open得到,打开的是一个磁盘文件。

                    注意:文件的大小不能为0;

                          open指定的权限,不能和prot冲突;

                          port:PROT_READ; open:只读/读写;

                          port:PROT_READ|PROT_WRITE; open:读写;

                          总的来说:port的权限要小于open的权限,必须要有读的权限。

                -offset:偏移量,一般不用,必须要指定的是4k的整数倍。0表示不偏移。

        返回值:

                -成功:返回创建内存的首地址;

                -失败:返回MAP_FAILED (void *)-1;

2、munmap函数 

涉及头文件:#include<sys/mman.h>

函数原型:int munmap(void *addr, size_t length);

功能:释放内存映射;

参数:

            void *addr:释放的内存的首地址;

            length:要释放的内存的大小,要和mmap函数中的length的值一样。

2、案例一:通过内存映射实现父子进程间的通信

实现方案:

        在没有子进程的时候,通过唯一的父进程创建内存映射区;

        有了内存映射区,再创建子进程;

        父子进程共享内存映射区;

实现流程:

        1、打开一个文件;

        2、获取文件大小(用于mmap函数的参数);

        3、创建内存映射区;fork()之后父子进程共享内存映射区。

        4、创建子进程;

               父进程读取数据,子进程发送数据;(因为子进程发送完成后,可以被父进程进行回收,避免僵尸进程的产生)。

#include <stdio.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <sys/mman.h>
#include <string.h>
#include <stdlib.h>int main()
{//1、打开一个文件int fd = open("text.txt",O_RDWR);//2、获取大小int size=lseek(fd,0,SEEK_END);//3、创建内存映射区void *ptr =  mmap(NULL,size,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);if(ptr==MAP_FAILED){perror("mmap");exit(0);}//4、创建子进程pid_t pid = fork();if(pid>0){wait(NULL);//父进程:char buf[64];strcpy(buf,(char *)ptr );printf("read data:%s\n",buf);}else if(pid==0){//子进程:strcpy((char *)ptr,"nihao,sun!!");}//关闭内存映射区:munmap(ptr,size);return 0;
}

运行结果:

3、案例二:通过内存映射实现没有关系进程之间的通信

实现方案:

        准备一个大小不为0的磁盘文件;

        进程1 通过磁盘文件(与进程2的文件相同)创建内存的映射区;

                  得到一个操作这块内存的指针。

        进程2 通过磁盘文件(与进程1的文件相同)创建内存映射区;

                  得到一个操作这块内存的指针。

                  使用内存映射区进行通信。

 注意:内存映射区通信,没有阻塞;

进程1:写内容

#include <stdio.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <sys/mman.h>
#include <string.h>
#include <stdlib.h>int main()
{// 1、准备一个磁盘文件。// 2、通过磁盘文件创建内存的映射区;int fd = open("test.txt",O_RDWR);int size= lseek(fd,0,SEEK_END);void * prt=mmap(NULL,size,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);if( prt == MAP_FAILED){perror("mmap");exit(0);}strcpy((char *)prt,"sixsixsix");munmap(prt,size);return 0;
}

进程2:读文件

#include <stdio.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <sys/mman.h>
#include <string.h>
#include <stdlib.h>int main()
{// 1、准备一个磁盘文件。// 2、通过磁盘文件创建内存的映射区;int fd = open("test.txt",O_RDWR);int size= lseek(fd,0,SEEK_END);void * prt=mmap(NULL,size,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);if( prt == MAP_FAILED){perror("mmap");exit(0);}char buf[64];strcpy(buf,(char *)prt);printf("read data:%s\n",buf);munmap(prt,size);return 0;
}

运行结果: 

4、内存映射的注意事项

1、如果对mmap的返回值(ptr)做++操作,munmap能够成功吗?
    void * ptr =mmap(...)
    可以对其进行++操作,但是不建议因为释放的时候,需要把最开始的地址记录下来。
2、如果open时,O_RDONLY,mmap时prot参数指定 PROT_READ|PROT_WRITE 会怎么样?
    错误,会返回宏MAP_FAILED
    open()权限建议和prot参数保持一致,更准确的说open()的权限要大于prot参数的权限;
3、如果文件偏移量为1000会怎么样?
    偏移量必须是4k的整数倍,否则 错误,会返回宏MAP_FAILED
4、mmap什么情况下会调用失败?
    -第二个参数:length=0;
    -第三个参数:prot权限
                    -只是指定了写权限;
                    -prot参数权限为:PROT_READ|PROT_WRITE,第5个参数文件描述符fd(通过open函数打开时,O_RDONLY、O_WRONLY)
5、可以open的时候,O_CREAT一个新文件来创建映射区。
    可以的,但是创建的文件的大小如果为0,肯定不行;
    -lseek()
    -truncate()
    进行扩展;
6、mmap后关闭文件描述符,对mmap映射有没有影响?
    int fd=open("xxx");
    mmap(,,,,fd,0);
    close(fd);
    映射区还存在,创建映射区的fd被关闭,没有任何影响;
7、对ptr进行越界操作会怎么?
    void *ptr=mmap(NULL,100..);
    4k
    越界操作,操作的是非法内存,-段错误。

5、使用内存映射实现文件的拷贝

使用内存映射实现文件拷贝的功能

/*

    1、对原始的文件进行内存映射;

    2、创建一个新的文件,新文件进行扩展;

    3、把新文件的数据映射到内存中;

    4、通过内存拷贝,将第一个文件的内存数据拷贝到新的文件内存中;

    5、释放资源;

*/

#include <stdio.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
int main()
{// 1、对原始的文件进行内存映射;int fd =open("english.txt",O_RDWR);if(fd==-1){perror("open");exit(0);}//获取原始文件的大小int len=lseek(fd,0,SEEK_END);// 2、创建一个新的文件,新文件进行扩展;int fd1 =open("cpy.txt",O_RDWR|O_CREAT,0664);if(fd1==-1){perror("open");exit(0);}//对新创建的文件进行拓展truncate("cpy.txt",len);write(fd," ",1);//3、分别做内存映射void * ptr= mmap(NULL,len,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);void * ptr1= mmap(NULL,len,PROT_READ|PROT_WRITE,MAP_SHARED,fd1,0);if(ptr == MAP_FAILED){perror("mmap");exit(0);}if(ptr1 == MAP_FAILED){perror("mmap");exit(0);}//内存拷贝memcmp(ptr1,ptr,len);//释放资源munmap(ptr1,len);munmap(ptr,len);close(fd1);close(fd);return 0;
}

 运行结果:

6、父子进程间匿名内存映射

  匿名映射不需要文件实体,直接进行内存映射。在父子进程中可以使用匿名映射。没有关系的进程不能进行,没有关联了。

void *mmap(void *addr, size_t length, int prot, int flags,int fd, off_t offset);

关键在于:port需要用到MAP_ANONYMOUS,此参数是匿名映射所需要的。

#define _DEFAULT_SOURCE 
#include <stdio.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <sys/mman.h>
#include <string.h>
#include <stdlib.h>int main()
{//1、创建匿名内存映射区int len =4096;void *ptr = mmap(NULL,len,PROT_READ|PROT_WRITE ,MAP_SHARED | MAP_ANONYMOUS,-1,0);//if(ptr==MAP_FAILED){perror("mmap");exit(0);}//2、父子进程通信pid_t pid=fork();if(pid>0){//父进程strcmp((char*)ptr,"hello,world");wait(NULL);}else if(pid==0){//子进程sleep(1);printf("%s\n",(char*)ptr);}//释放内存映射区int ret=munmap(ptr,len);if(ret==-1){perror("munmap");exit(0);}int ret1=munmap(ptr,len);if(ret1==-1){perror("munmap");exit(0);}}

运行结果:

 以上便是进程间内存映射的相关知识,结合案例进行了分析,大家学习后一定要多多练习!!

创作不易,还请多多点赞支持!!!

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

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

相关文章

代码随想录-Day46

121. 买卖股票的最佳时机 给定一个数组 prices &#xff0c;它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格。 你只能选择 某一天 买入这只股票&#xff0c;并选择在 未来的某一个不同的日子 卖出该股票。设计一个算法来计算你所能获取的最大利润。 返回你可以从…

【JVM-05】Java内存区域(运行时数据区)、对象创建过程、内存布局

【JVM-05】Java内存区域即运行时数据区、对象创建过程、内存布局 1. 介绍下Java内存区域(运行时数据区)1.1 程序计数器(线程私有)1.2 虚拟机栈(线程私有)1.3 本地方法栈(线程私有)1.4 Java堆(线程共享)1.5 方法区(线程共享)1.5.1 方法区和永久代的关系1.5.2 常用参数1.5.3 为什…

Halcon支持向量机

一 支持向量机 1 支持向量机介绍&#xff1a; 支持向量机(Support Vector Machine&#xff0c;SVM)是Corinna Cortes和Vapnik于1995年首先提出的&#xff0c;它在解决小样本、非线性及高维模式识别表现出许多特有的优势。 2 支持向量机原理: 在n维空间中找到一个分类超平面…

node与npm安装教程

node与npm的下载安装教程&#xff1a; 文章目录 node与npm的下载安装教程&#xff1a;---Node.js 介绍NPM 介绍 一&#xff1a;下载&#xff08;node与npm的安装包是在一起的&#xff09;二&#xff1a;安装1&#xff1a;双击运行安装文件1-node-v14.15.0-x64.msi,点击下一步。…

常用渲染管线介绍

1、光栅化渲染管线&#xff08;Raster pipeline&#xff09; 1.1、光栅化概述 光栅化图形渲染管线是实时渲染的核心组件。渲染管线的功能是通过给定虚拟相机、3D场景物体以及光源等场景要素来产生或者渲染一副2D的图像。如上图所示&#xff0c;场景中的3D物体通过管线转变为屏…

动态渲染dom

最近在做类似论文生成的一个系统&#xff0c;比较复杂&#xff0c;简单来说就是文字、图表的展示&#xff0c;但是顺序不固定&#xff0c;所以有动态渲染dom的需求&#xff0c;以下是我写的小demo&#xff0c;以作记录。 <template><div id"app"><div…

Datadog Dash 2024 新功能解析

Datadog 2024 年的 Dash 刚刚落下帷幕&#xff0c;作为正在与 Datadog 开始竞争的观测云&#xff0c;我们认真仔细的分析了 Datadog 的每一个新功能&#xff0c;发现一些很有意思的事情&#xff0c;今天就给大家做一次全面的分析。&#xff08;所有 Datadog 的 Dash 的最新功能…

基于改进YOLOv5s的跌倒行为检测 | 引入SKAttention注意机制 + 引入空间金字塔池化结构SPPFCSPC + 结合ASFF自适应空间融合

前言&#xff1a;Hello大家好&#xff0c;我是小哥谈。为了实现电厂人员跌倒行为的实时检测&#xff0c;防止跌倒昏迷而无法及时发现并救援的事件发生&#xff0c;针对跌倒行为检测实时性以及特征提取能力不足的问题&#xff0c;提出了一种改进YOLOv5s的跌倒行为检测算法网络&a…

PD虚拟机和VirtualBox有什么区别?Parallels Desktop 19.1.1 破解版

随着计算机技术的不断发展&#xff0c;虚拟机软件在现代信息技术领域中扮演着越来越重要的角色。虚拟机不仅可以帮助用户在一台物理机器上运行多个操作系统&#xff0c;还能有效隔离不同环境&#xff0c;提升系统安全性。在众多的虚拟机软件中&#xff0c;PD虚拟机&#xff08;…

第一百三十八节 Java数据类型教程 - Java boolean数据类型和float数据类型

Java数据类型教程 - Java boolean数据类型 布尔数据类型只有两个有效值:true和false。 这两个值称为布尔值字面量。 我们可以使用布尔值字面量 boolean done; // Declares a boolean variable named done done true; // Assigns true to done布尔变量不能转换为任何其他…

ESP32-VScode环境设置

目录 前言 一、安装VSCode 二、安装ESP32环境 1.安装ESP-IDF 2.ESP-IDF设置 3:开始配置环境 4.打开example进行验证 5.烧录 6.调整波特率 总结 前言 环境&#xff1a;Visual Studio Code 芯片&#xff1a;ESP32 说实话&#xff0c;这是我装的时间最长的一个环境&…

汇聚荣拼多多电商哪些热词比较受关注?

汇聚荣拼多多电商哪些热词比较受关注?在探讨拼多多电商平台的热点关键词时&#xff0c;我们首先得明确&#xff0c;这个平台因其独特的商业模式和市场定位&#xff0c;吸引了大量消费者的目光。拼多多通过“拼团”购物的方式迅速崛起&#xff0c;成为电商行业的一个重要力量。…

2024年用scrapy爬取BOSS直聘的操作

SCrapy框架实现对BOSS直聘的爬取 文章目录 SCrapy框架实现对BOSS直聘的爬取对SCrapy框架的一个简单认识Scrapy 组件的作用Scrapy 数据流 1. 测试反爬2. 定义一个下载中间件类,截取spiders的请求&#xff08;中间件直接截取请求&#xff0c;并且返回给Spider进行数据解析&#x…

【最新鸿蒙应用开发】——用户信息封装

用户管理工具封装 1. 为什么要封装 在进行如下登录功能时&#xff0c; 通常需要将一些用户信息以及token进行持久化保存&#xff0c;以方便下次进行数据请求时携带这些用户信息来进行访问后端数据。下面分享一下鸿蒙当中实用的持久化封装操作。 2. 步骤 封装用户信息管理工具…

Mybatis Plus 自动填充注解 @TableField(fill = FieldFill.INSERT_UPDATE)

第一步&#xff1a;在需要自动填充的位置加上注解 通过在创建时间和修改时间上添加 fill 填充字段 进行自动填充 第二步&#xff1a;要想实现自动填充还需要实现MetaObjectHandler接口&#xff0c;在这里实现自动填充的逻辑 Component public class MyMetaObjectHandler …

tinyshop项目部署

参考软件测试之测试用例设计&#xff08;四&#xff09;_管理后台 测试用例-CSDN博客 1、下载xampp 2、修改apache和mysql的端口分别为4431 &#xff0c;8013和3306 3、访问页面&#xff1a;输入ip:端口号&#xff0c;出现以下页面即成功 4、安装tinyshop商城 将解压的tinys…

动态住宅代理IP详细解析

在大数据时代的背景下&#xff0c;代理IP成为了很多企业顺利开展的重要工具。代理IP地址可以分为住宅代理IP地址和数据中心代理IP地址。选择住宅代理IP的好处是可以实现真正的高匿名性&#xff0c;而使用数据中心代理IP可能会暴露自己使用代理的情况。 住宅代理IP是指互联网服务…

Transformation(转换)开发-switch/case组件

一、switch/case组件-条件判断 体育老师要做一件非常重要的事情&#xff1a;判断学生是男孩还是女孩、或者是蜘蛛&#xff0c;然后让他们各自到指定的队伍中 体育老师做的事情&#xff0c;我们同样也会在Kettle中会经常用来。在Kettle中&#xff0c;switch/case组件可以来做类似…

【等保2.0的内容有哪些?】

“在“等保2.0”的基础上&#xff0c;分别增加了云计算安全、移动互联安全、物联网安全、工控系统安全、大数据安全5个拓展需求。 《中华人民共和国刑法》第253条&#xff0c;非法将公民个人资料卖给他人&#xff0c;并处罚金。 违反国家相关法律法规&#xff0c;将其在执行公…

vue2使用use注册自定义指令实现输入控制与快捷复制

使用场景 在一些form表单填写内容的时候&#xff0c;要限制输入的内容必须是数值、浮点型&#xff0c;本来el-input-number就可以实现&#xff0c;但是它本身带那个数值控制操作&#xff0c;等一系列感觉不舒服的地方。如果只是使用el-input该多好&#xff0c;只要监听一下输入…