mmap内存映射

article/2025/10/23 20:26:34

内存映射通信

一、mmap (memory_map)

1.1 简介

存储映射I/O (Memory-mapped I/O) 使一个磁盘文件与存储空间中的一个缓冲区相映射。于是当从缓冲区中取数据,就相当于读文件中的相应字节。于此类似,将数据存入缓冲区,则相应的字节就自动写入文件。这样,就可在不适用read和write函数的情况下,使用地址(指针)完成I/O操作。使用这种方法,首先应通知内核,将一个指定文件映射到存储区域中。这个映射工作可以通过mmap函数来实现。

在这里插入图片描述

1.2 mmap函数

void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);参数:addr: 指定映射区的首地址。通常传 NULL,表示让系统自动分配length:共享内存映射区的大小。(<= 文件的实际大小)*如果使用length > 文件大小,那么就会出现总线错误*prot: 共享内存映射区的读写属性。PROT_READ、PROT_WRITE、PROT_READ|PROT_WRITEflags: 标注共享内存的共享属性。MAP_SHARED、MAP_PRIVATE  shared 意思是修改会反映到磁盘上private 表示修改不反映到磁盘上fd: 用于创建共享内存映射区的那个文件的 文件描述符。
offset:默认 0,表示映射文件全部。偏移位置。需是 4k 的整数倍。
返回值:成功:映射区的首地址。失败:MAP_FAILED (void*(-1)), errno

二、程序例程

2.1 mmap建立映射区

#include <sys/mman.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>void sys_err(const char* str){perror(str);exit(1);
}/*
mmap:memorty_map 内存映射试验
*/
int main(int argc,char* argv[]){char *p = NULL; //用于接收mmap的返回地址int fd; //用于文件的接收fd = open("testmmap", O_RDWR | O_CREAT | O_TRUNC, 0664);if(fd == -1){//打开失败sys_err("open error");}/*lseek(fd, 9, SEEK_END);  //将文件给扩展长度到10write(fd, "\0", 1);*/ftruncate(fd,10); //将文件给扩展长度到10int len = lseek(fd, 0, SEEK_END);//获取文件的长度//将文件全部进行内存映射p = (char*)mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);if(p == MAP_FAILED){sys_err("mmap error");}close(fd);strcpy(p, "hello\n");//进行写操作printf("------%s\n",p);//打印int ret = munmap(p,len);//解除映射if(ret == -1){sys_err("munmap error");}return 0;
}

运行结果

haitu@ubuntu:/opt/modbus_test/linux_test/mmap$ ls
makefile  mmap_test  mmap_test.c  testmmap
haitu@ubuntu:/opt/modbus_test/linux_test/mmap$ cat testmmap 
hello
haitu@ubuntu:/opt/modbus_test/linux_test/mmap$ ./mmap_test 
------hellohaitu@ubuntu:/opt/modbus_test/linux_test/mmap$ 

2.2 使用注意事项

  1. 用于创建映射区的文件大小为 0,实际指定非 0 大小创建映射区,出 “总线错误”。

  2. 用于创建映射区的文件大小为 0,实际制定 0 大小创建映射区, 出 “无效参数”。

  3. 用于创建映射区的文件读写属性为,只读。映射区属性为 读、写。 出 “无效参数”。

  4. 创建映射区,需要 read 权限。当访问权限指定为 “共享”MAP_SHARED 时, mmap 的读写权

限,应该 <=文件的 open 权限。

只写不行。

  1. 文件描述符 fd,在 mmap 创建映射区完成即可关闭。后续访问文件,用 地址访问。

  2. offset 必须是 4096 的整数倍。(MMU 映射的最小单位 4k )

  3. 对申请的映射区内存,不能越界访问。

  4. munmap 用于释放的 地址,必须是 mmap 申请返回的地址。

  5. 映射区访问权限为 “私有”MAP_PRIVATE, 对内存所做的所有修改,只在内存有效,不会反

应到物理磁盘上。

  1. 映射区访问权限为 “私有”MAP_PRIVATE, 只需要 open 文件时,有读权限,用于创建映射

区即可。

3.3 进行函数封装

借鉴malloc和free函数原型,写自定义函数smalloc,sfree来完成映射区的建立和释放

#include <sys/mman.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>void sys_err(const char* str){perror(str);exit(1);
}//实现类似c语言中的malloc
/*** len:创建内存映射的长度* filename:文件名* void* 返回值,内存映射的首地址*/
void *smalloc(int len,char *filename){void *p = NULL;int fd = open(filename, O_RDWR | O_CREAT | O_TRUNC, 0664);if(fd == -1){perror("open error");  //文件打开失败return NULL;}ftruncate(fd,len); //对文件进行扩展int fileLen = lseek(fd, 0, SEEK_END); //获取文件的长度//对文件的全部进行处理成全映射p = (char*)mmap(NULL, fileLen, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);if(p == MAP_FAILED){ //如果没有实现映射的话sys_err("mmap error");return MAP_FAILED;//实际上就是(void*)(-1)}return p;
}/*** p:创建的内存映射首地址* len:创建内存映射的长度*/
int sfree(void * p,int len){int ret = munmap(p,len);if(ret == -1){perror("munmap error");return -1;}return 1;
}int main(int argc,char* argv[]){char *p = NULL; //用于接收mmap的返回地址//int fd; //用于文件的接收p = (char *)smalloc(20, "smallocTest");strcpy(p, "hello nihao\n");printf("--------%s", p);int ret = sfree((void *)p,20);if(ret == 1){printf("munmap success");}else{printf("munmap error");}return 0;
}

函数执行结果:

haitu@ubuntu:/opt/modbus_test/linux_test/mmap$ ./smalloc 
--------hello nihao
munmap successhaitu@ubuntu:/opt/modbus_test/linux_test/mmap$ ls
makefile  mmap_test  mmap_test.c  smalloc  smalloc.c  smallocTest  testmmap
haitu@ubuntu:/opt/modbus_test/linux_test/mmap$ cat smallocTest 
hello nihao
haitu@ubuntu:/opt/modbus_test/linux_test/mmap$ 

三、父子进程之间的mmap通信

父子进程使用 mmap 进程间通信:

父进程 先 创建映射区。 open( O_RDWR) mmap( MAP_SHARED );

指定 MAP_SHARED 权限 fork() 创建子进程。

一个进程读, 另外一个进程写。

#include <sys/mman.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>void sys_err(const char* str){perror(str);exit(1);
}int var = 100;/*
mmap:memorty_map 内存映射试验
*/
int main(int argc,char* argv[]){char *p = NULL; //用于接收mmap的返回地址int fd; //用于文件的接收pid_t pid;fd = open("testmmap", O_RDWR | O_CREAT | O_TRUNC, 0664);if(fd == -1){//打开失败sys_err("open error");}/*lseek(fd, 9, SEEK_END);  //将文件给扩展长度到10write(fd, "\0", 1);*/ftruncate(fd,10); //将文件给扩展长度到10int len = lseek(fd, 0, SEEK_END);//获取文件的长度//将文件全部进行内存映射p = (char*)mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);if(p == MAP_FAILED){sys_err("mmap error");}close(fd);/*int flag = unlink("testmmap");  //--将文件删除if(flag == -1){perror("unlink error");exit(1);}*/pid = fork();//创建子进程if(pid == 0){*p = 20;  //写共享内存var = 1000;printf("child ,*p=%d,var=%d\n",*p,var);}else{sleep(1);printf("parent,*p=%d,var = %d\n",*p,var);}int ret = munmap(p,len);//解除映射if(ret == -1){sys_err("munmap error");}return 0;
}

执行结果:

haitu@ubuntu:/opt/modbus_test/linux_test/mmap$ ./mmap_parent_son 
child ,*p=20,var=1000
parent,*p=20,var = 100
haitu@ubuntu:/opt/modbus_test/linux_test/mmap$ 注意:如果上面的p = (char*)mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
改为:p = (char*)mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);那么就无法进行父子进程之间的通信。

四、无血缘关系之间的通信

就上面的程序进行更改

4.1 写进程 mmap_w.c程序

#include <sys/mman.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>void sys_err(const char* str){perror(str);exit(1);
}int var = 100;
/*
mmap:memorty_map 内存映射试验
*/
int main(int argc,char* argv[]){char *p = NULL; //用于接收mmap的返回地址int fd; //用于文件的接收fd = open("testmmap", O_RDWR | O_CREAT | O_TRUNC, 0664);  //打开文件testmmap用作映射if(fd == -1){//打开失败sys_err("open error");}/*lseek(fd, 9, SEEK_END);  //将文件给扩展长度到10write(fd, "\0", 1);*/ftruncate(fd,10); //将文件给扩展长度到10int len = lseek(fd, 0, SEEK_END);//获取文件的长度//将文件全部进行内存映射p = (char*)mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);if(p == MAP_FAILED){sys_err("mmap error");}close(fd);while(1){memcpy(p,&var,sizeof(var));  //往里面写var值var++;  //var值时刻变化sleep(1);}int ret = munmap(p,len);//解除映射if(ret == -1){sys_err("munmap error");}return 0;
}

4.2 读进程 mmap_r.c

#include <sys/mman.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>void sys_err(const char* str){perror(str);exit(1);
}int var = 100;/*
mmap:memorty_map 内存映射试验
*/
int main(int argc,char* argv[]){char *p = NULL; //用于接收mmap的返回地址int fd; //用于文件的接收fd = open("testmmap", O_RDONLY);if(fd == -1){//打开失败sys_err("open error");}/*lseek(fd, 9, SEEK_END);  //将文件给扩展长度到10write(fd, "\0", 1);*///ftruncate(fd,10); //将文件给扩展长度到10int len = lseek(fd, 0, SEEK_END);//获取文件的长度//将文件全部进行内存映射p = (char*)mmap(NULL, len, PROT_READ , MAP_SHARED, fd, 0);if(p == MAP_FAILED){sys_err("mmap error");}close(fd);while(1){printf("%d\n",*p);sleep(2);}int ret = munmap(p,len);//解除映射if(ret == -1){sys_err("munmap error");}return 0;
}

4.3 结果

写进程打开
haitu@ubuntu:/opt/modbus_test/linux_test/mmap$ ./mmap_w
读进程显示
haitu@ubuntu:/opt/modbus_test/linux_test/mmap$ ./mmap_r
0
104
106
108
110
112
114
116
118
120
122
124
126
^C
haitu@ubuntu:/opt/modbus_test/linux_test/mmap$ 注意:多个写端一个读端也没问题,打开多个写进程即可,读进程会读到所有写进程写入的内容。这里要特别注意,内容被读走之后不会消失,所以如果读进程的读取时间间隔短,它会读到很多重复内容,就是因为写进程没来得及写入新内容,内容没有被覆盖掉。

五、匿名映射

实质上mmap是内核借助文件帮我们创建了一个映射区,多个进程之间利用该映射区完成数据传递。由于内核空间多进程共享,因此无血缘关系的进程间也可以使用mmap来完成通信。只要设置相应的标志位参数flags即可。若想实现共享,当然应该使用MAP_SHARED了

int *p = NULL;
p = (int *)mmap(NULL, 40, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0);//创建映射
//----- 内存映射内容
munmap(p,40) //清除映射
注意:匿名映射:只能用于 血缘关系进程间通信。

例子程序:

#include <sys/mman.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>void sys_err(const char* str){perror(str);exit(1);
}int var = 100;/*
mmap:memorty_map 内存映射试验
*/
int main(int argc,char* argv[]){char *p = NULL; //用于接收mmap的返回地址pid_t pid;p = (char*)mmap(NULL, 40, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);if(p == MAP_FAILED){sys_err("mmap error");}pid = fork();//创建子进程if(pid == 0){*p = 20;  //写共享内存var = 1000;printf("child ,*p=%d,var=%d\n",*p,var);}else{sleep(1);printf("parent,*p=%d,var = %d\n",*p,var);}int ret = munmap(p,40);//解除映射if(ret == -1){sys_err("munmap error");}return 0;
}

http://chatgpt.dhexx.cn/article/jVaN9yun.shtml

相关文章

Linux编程之mmap示例

一、问题背景 Linux下&#xff0c;针对文件读写操作&#xff0c;一般有三个步骤&#xff1a; 1&#xff09;把文件内容读入到内存中&#xff1b;调用read&#xff08;系统调用&#xff09;&#xff0c;从内核态读取文件内容到虚拟内存&#xff1b; 2&#xff09;修改内存中的内…

【mmap】深度分析mmap:是什么 为什么 怎么用 性能总结

目录 有什么用&#xff1f; 1、文件映射 2、分配内存&#xff08;匿名文件映射&#xff09; mmap基础概念 mmap内存映射原理 mmap和常规文件操作的区别 mmap优点总结 mmap相关函数 mmap使用细节 性能总结 效率对比 有什么用&#xff1f; 将一个文件或者其它对象映射…

mmap使用

linux进程虚拟地址空间中存在一段称为mmap的内存区&#xff0c;当申请用户内存较大时&#xff0c;如大于128kb&#xff0c;系统一般会通过mmap系统调用直接映射一片内存区&#xff0c;使用结束后再通过ummap系统调用归还。关于mmap的原理网上有很多文档&#xff0c;这里不再赘述…

MMAP技术

1. mmap 基础概念 mmap 即 memory map&#xff0c;也就是内存映射。 mmap 是一种内存映射文件的方法&#xff0c;即将一个文件或者其它对象映射到进程的地址空间&#xff0c;实现文件磁盘地址和进程虚拟地址空间中一段虚拟地址的一一对映关系。实现这样的映射关系后&#xff…

mmap在嵌入式中的应用

大概雍正皇帝怎么也不会想到&#xff0c;自己在西历2022年的男生和女生眼里&#xff0c;会是截然不同的两种形象。 1 以我对身边同学朋友的观察&#xff0c;男生们大多爱看《雍正王朝》&#xff0c;他们眼中的雍正&#xff0c;大约是个推行了“火耗归公”、“摊丁入亩”等遏制…

Linux mmap原理

Linux mmap原理 前言Linux段页式内存管理mmapmmap内存映射原理文字概述mmap函数参数介绍源码解析1. 文件映射2. 缺页异常 mmap 和常规文件操作的区别mmap 使用的细节 小结 前言 mmap是linux操作系统提供给用户空间调用的内存映射函数&#xff0c;很多人仅仅只是知道可以通过mm…

Linux内存管理之mmap

目录 一. mmap系统调用 1. mmap系统调用 2. 系统调用munmap() 3. 系统调用msync() 二. 系统调用mmap()用于共享内存的两种方式&#xff1a; 三. mmap进行内存映射的原理 一. mmap系统调用 1. mmap系统调用 mmap将一个文件或者其它对象映射进内存。文件被映射到多…

Linux内核黑科技——mmap实现详解

前言&#xff1a;故事的开始是这样的&#xff0c;某天在脉脉上看到有人发了下面的帖子&#xff1a; 想不到 mmap 都成了黑科技了&#xff0c;为了让大家都能了解这个黑科技&#xff0c;所以还是写篇文章来详细介绍一下 mmap 的实现吧。 其实&#xff0c;源码分析是比较难写的&…

【Linux】Linux编程之 mmap解析

前言 虚拟内存系统通过将虚拟内存分割为称作虚拟页(Virtual Page&#xff0c;VP)大小固定的块&#xff0c;一般情况下&#xff0c;每个虚拟页的大小默认是4096字节。同样的&#xff0c;物理内存也被分割为物理页(Physical Page&#xff0c;PP)&#xff0c;也为4096字节。 一、…

讲一讲什么是 MMAP

1. mmap 基础概念 mmap 即 memory map&#xff0c;也就是内存映射。 mmap 是一种内存映射文件的方法&#xff0c;即将一个文件或者其它对象映射到进程的地址空间&#xff0c;实现文件磁盘地址和进程虚拟地址空间中一段虚拟地址的一一对映关系。实现这样的映射关系后&#xff…

人工神经网络的应用有哪些方面,人工神经网络在生活中的应用

人工神经网络的应用 人工神经网络&#xff08;Artificial Neural Network&#xff0c;简称ANN &#xff09;&#xff0c;以数学模型模拟神经元活动&#xff0c;是基于模仿大脑神经网络结构和功能而建立的一种信息处理系统。人工神经网络具有自学习、自组织、自适应以及很强的非…

人工神经网络有哪些算法,神经网络都有哪些算法

人工神经网络分类方法 从20世纪80年代末期&#xff0c;人工神经网络方法开始应用于遥感图像的自动分类。 目前&#xff0c;在遥感图像的自动分类方面&#xff0c;应用和研究比较多的人工神经网络方法主要有以下几种&#xff1a;&#xff08;1&#xff09;BP&#xff08;BackP…

深度学习-人工神经网络概述

人工神经网络 简述 很多术语听起来很唬人&#xff0c;“人工神经网络”就属于其中之一。在很多人看来&#xff0c;我们对人类的神经系统还没有研究透彻&#xff0c;这就来了一个“人工的”神经网络&#xff0c;人脑这样复杂&#xff0c;那么人工神经网络一定相当高深莫测。如果…

人工神经网络的应用实例,人工神经网络实际应用

神经网络算法实例说明有哪些&#xff1f; 在网络模型与算法研究的基础上&#xff0c;利用人工神经网络组成实际的应用系统&#xff0c;例如&#xff0c;完成某种信号处理或模式识别的功能、构作专家系统、制成机器人、复杂系统控制等等。 纵观当代新兴科学技术的发展历史&…

人工神经网络算法实战教程

神经网络&#xff08;Artificial Neural Network&#xff0c;也称为人工神经网络&#xff0c;简称ANN&#xff09;具有通过示例学习能力。ANN是受生物神经元系统启发的的信息处理模型&#xff0c;它由大量高度互联的处理元素组成&#xff0c;这些处理元素被称神经元&#xff0c…

人工神经网络的三个要素,神经网络三要素是指

一个完整的人工神经网络包括 人工神经网络主要架构是由神经元、层和网络三个部分组成。整个人工神经网络包含一系列基本的神经元、通过权重相互连接。神经元是人工神经网络最基本的单元。 单元以层的方式组&#xff0c;每一层的每个神经元和前一层、后-层的神经元连接&#x…

人工神经网络连接方式,全连接神经网络作用

人工神经元网络的拓扑结构主要有哪几种&#xff1f;谢谢大侠~~~ 神经网络的拓扑结构包括网络层数、各层神经元数量以及各神经元之间相互连接的方式。人工神经网络的模型从其拓扑结构角度去看&#xff0c;可分为层次型和互连型。 层次型模型是将神经网络分为输入层&#xff08…

神经网络算法的具体流程,人工神经网络算法步骤

神经网络 算法 思路&#xff1f;能否提供一个最简单的代码&#xff1f; 30 。 最基本的BP算法&#xff1a;1&#xff09;正向传播&#xff1a;输入样本&#xff0d;>输入层&#xff0d;>各隐层&#xff08;处理&#xff09;&#xff0d;>输出层注1&#xff1a;若输出…

人工神经网络的基本原理

1.1 人工神经网络原理 MeCulloch 和 Pitts 基于对大脑神经元的研究提 出了人工神经元模型&#xff08;M-P 模型&#xff09;。人工神经元模型如下图所示。 M-P模型把神经元看作n个的输入对应产生1个输出&#xff0c;该模型的函数的表达式如下&#xff1a; 该表达式中W[W1,W2,W3…

人工智能神经网络的应用,人工神经网络最新应用

人工智能在如今人们的现实生活中&#xff0c;都有哪些趣味十足的应用&#xff1f; 人工智能&#xff0c;也被称为AI。研究和开发模拟、扩展和扩展人类智能的理论、方法、技术和应用系统是一门新兴的技术科学。 人工智能是计算机科学的一个分支&#xff0c;它试图理解智能的本…