【Linux系统编程】25.mmap、munmap

目录

mmap

参数addr

参数length

参数prot

参数flags

参数fd

参数offset

返回值

保险使用方式

munmap

参数addr

参数length

返回值

测试代码1

测试结果

使用注意事项

测试代码2

测试结果

测试代码3

测试结果

匿名映射

测试代码4

测试结果

mmap

将一个指定文件映射到存储区域中。

man 2 mmap

参数addr

指定映射区的首地址。通常传NULL,让系统自动分配。

参数length

共享内存映射区的大小,小于等于文件的实际大小。

参数prot

共享内存映射区的读写属性,映射区权限。

可传参数:

  • PROT_READ

  • PROT_WRITE

  • PROT_READ|PROT_WRITE

参数flags

标注共享内存的共享属性,标志位参数,常用于设定更新物理区域、设置共享、创建匿名映射区。

可传参数:

  • MAP_SHARED:会将映射区所做的操作反映到物理设备(磁盘)上。

  • MAP_PRIVATE:映射区所做的修改不会反映到物理设备。

参数fd

用于创建共享内容映射区的文件的文件描述符。

参数offset

偏移位置,必须是4k的整数倍

0:默认值,表示映射文件全部。

返回值

成功:映射区的首地址。

失败:MAP_FAILED。

保险使用方式

fd=open("文件名",O_RDWR);
data=mmap(NULL,有效文件大小,PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);

munmap

释放映射区。

参数addr

映射区首地址。

参数length

映射区大小。

返回值

成功:0

失败:-1

测试代码1

建立文件映射,读取并写入其他内容。

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <sys/mman.h>int main(int argc, char *argv[])
{int fd, flag;char *data = NULL;char data1[1024];int leng;printf("程序开始运行。\n");printf("开始打开文件。\n");fd = open("temp.txt", O_RDWR);if (fd == -1){perror("打开文件错误");exit(1);}printf("打开文件完成。\n");printf("开始文件映射。\n");leng = lseek(fd, 0, SEEK_END);data = mmap(NULL, leng, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); //全部映射if (data == MAP_FAILED){perror("文件映射错误");exit(1);}printf("文件映射完成。\n");printf("地址是%d。\n", *data);printf("内容是:%s", data);printf("开始写入文件。\n");printf("写入的内容是:hello,world.\n");strcpy(data, "hello,world.\n");printf("写入文件完成。\n");close(fd);return 0;
}

测试结果

映射多大的内存空间,只能写入多大的内存空间。映射后的返回值是文件里的内容。

 

使用注意事项

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

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

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

  4. 创建映射区需要read权限,当访问权限指定为“共享/MAP_SHARED”时,mmap的读写权限应该小于等于文件的open权限。

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

  6. offset必须是4096的整数倍,因为MMU映射的最小单位为4k。

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

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

  9. 映射区访问权限为“私有/MAP_PRIVATE”时,对内存所做的所有修改,只在内存有效,不会反应到物理磁盘上。

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

测试代码2

父子进程间通过映射区进行通信。

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/wait.h>int main(int argc, char *argv[])
{int fd, flag;int *di_zhi;pid_t JinCheng_ID;int temp = 100;printf("程序开始运行。\n");printf("开始打开文件。\n");fd = open("temp2.txt", O_RDWR | O_CREAT | O_TRUNC, 0644);if (fd == -1){perror("打开文件错误");exit(1);}printf("打开文件完成。\n");printf("开始文件拓展。\n");ftruncate(fd, 10);printf("文件拓展完成。\n");printf("开始文件映射。\n");di_zhi = (int *)mmap(NULL, 10, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); //全部映射if (di_zhi == MAP_FAILED){perror("文件映射错误");exit(1);}close(fd);printf("文件映射完成。\n");printf("开始创建进程。\n");JinCheng_ID = fork();if (JinCheng_ID == 0) //子进程{*di_zhi = 1000;temp = 200;printf("这是子进程,*di_zhi=%d,temp=%d。\n", *di_zhi, temp);}else if (JinCheng_ID > 0) //父进程{sleep(1);printf("这是父进程,*di_zhi=%d,temp=%d。\n", *di_zhi, temp);wait(NULL);}printf("开始释放映射区。\n");flag = munmap(di_zhi, 10);printf("释放映射区完成。\n");return 0;
}

测试结果

测试代码3

两个毫无关系的进程通过映射区进行通信。

/*
CeShi3_1.c
发送数据的进程
*/
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <sys/mman.h>struct XueSheng
{int id;char ming_zi[256];int nian_ling;
};int main(int argc, char *argv[])
{int fd;struct XueSheng xue_sheng = {1, "张三", 20};struct XueSheng *di_zhi;printf("程序开始运行。\n");printf("开始打开文件。\n");fd = open("temp3.txt", O_RDWR | O_CREAT | O_TRUNC, 0644);if (fd == -1){perror("打开文件错误");exit(1);}printf("打开文件完成。\n");printf("开始文件拓展。\n");ftruncate(fd, sizeof(xue_sheng));printf("文件拓展完成。\n");printf("开始文件映射。\n");di_zhi = mmap(NULL, sizeof(xue_sheng), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); //全部映射if (di_zhi == MAP_FAILED){perror("文件映射错误");exit(1);}close(fd);printf("文件映射完成。\n");printf("开始向映射区发送数据。\n");while(1){memcpy(di_zhi,&xue_sheng,sizeof(xue_sheng));printf("发送的数据:id=%d,ming_zi=%s,nian_ling=%d。\n", di_zhi->id, di_zhi->ming_zi, di_zhi->nian_ling);xue_sheng.id++;sleep(1);}printf("开始释放映射区。\n");munmap(di_zhi, sizeof(xue_sheng));printf("释放映射区完成。\n");return 0;
}
/*
CeShi3_2.c
接收数据的进程
*/
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <sys/mman.h>struct XueSheng
{int id;char ming_zi[256];int nian_ling;
};int main(int argc, char *argv[])
{int fd;struct XueSheng xue_sheng;struct XueSheng *di_zhi;printf("程序开始运行。\n");printf("开始打开文件。\n");fd = open("temp3.txt", O_RDWR);if (fd == -1){perror("打开文件错误");exit(1);}printf("打开文件完成。\n");printf("开始文件映射。\n");di_zhi = mmap(NULL, sizeof(xue_sheng), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); //全部映射if (di_zhi == MAP_FAILED){perror("文件映射错误");exit(1);}close(fd);printf("文件映射完成。\n");printf("开始向映射区接收数据。\n");while (1){printf("接收的的数据:id=%d,ming_zi=%s,nian_ling=%d。\n", di_zhi->id, di_zhi->ming_zi, di_zhi->nian_ling);sleep(1);}printf("开始释放映射区。\n");munmap(di_zhi, sizeof(xue_sheng));printf("释放映射区完成。\n");return 0;
}

测试结果

匿名映射

只能用于血缘关系进程间的通信。

测试代码4

父子进程间使用匿名映射通信。

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/wait.h>int main(int argc, char *argv[])
{int flag;int *di_zhi;pid_t JinCheng_ID;int temp = 100;printf("程序开始运行。\n");printf("开始文件映射。\n");di_zhi = (int *)mmap(NULL, 1024, PROT_READ | PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0); //全部映射if (di_zhi == MAP_FAILED){perror("文件映射错误");exit(1);}printf("文件映射完成。\n");printf("开始创建进程。\n");JinCheng_ID = fork();if (JinCheng_ID == 0) //子进程{*di_zhi = 1000;temp = 200;printf("这是子进程,*di_zhi=%d,temp=%d。\n", *di_zhi, temp);}else if (JinCheng_ID > 0) //父进程{sleep(1);printf("这是父进程,*di_zhi=%d,temp=%d。\n", *di_zhi, temp);wait(NULL);}printf("开始释放映射区。\n");flag = munmap(di_zhi, 10);printf("释放映射区完成。\n");return 0;
}

测试结果

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

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

相关文章

可变参数(c/c++)

目录 一、C语言版本 二、C的实现方法 2.1数据包 2.2sizeof...运算符 2.3可变参数模板的使用 2.4emplace_back() 有时候我们在编写函数时&#xff0c;可能不知道要传入的参数个数&#xff0c;类型 。比如我们要实现一个叠加函数&#xff0c;再比如c语言中的printf,c中的emp…

Go语言每日一练——链表篇(九)

传送门 牛客面试笔试必刷101题 ----------------链表相加(二) 题目以及解析 题目 解题代码及解析 解析 这一道题主要是要对链表相加的过程进行模拟&#xff0c;虽然思路不难但是细节出比较多&#xff0c;这里博主的思路主要是先将两个链表反转过来然后以Head1为基础来模拟…

C语言:指针的基础详解

目录 1. 内存 2. 取地址& 3. 指针变量 4. 解引用 4.1 *解引用 4.2 []解引用 4.3 ->解引用 5. 指针变量的大小 5.1 结论 6. 指针运算 7. void* 指针 8. const修饰指针 8.1 const修饰变量 8.2 const修饰指针变量 8.3 结论 9. 野指针 9.1 为什么会出现野指…

[嵌入式系统-15]:RT-Thread -1- 简介与技术架构

目录 一、RT-Thread简介 1.1 简介 1.2 功能特点 1.3 发展历史 1.4 应用场合 1.5 与Linux的比较 1.6 ​​​​​​​RT-Thread优缺点 二、技术架构 2.1 分层架构​编辑 2.2 功能组件 2.3 应用程序接口RT-Thread API 2.4 应用程序接口&#xff1a;RT-Thread API、POS…

鸿蒙(HarmonyOS)项目方舟框架(ArkUI)之Navigation组件

鸿蒙&#xff08;HarmonyOS&#xff09;项目方舟框架&#xff08;ArkUI&#xff09;之Navigation组件 一、操作环境 操作系统: Windows 10 专业版、IDE:DevEco Studio 3.1、SDK:HarmonyOS 3.1 二、Navigation组件 鸿蒙&#xff08;HarmonyOS&#xff09;项目方舟框架&#…

Java图形化界面编程——AWT概论 笔记

2.3 Container容器 2.3.1 Container继承体系 Winow是可以独立存在的顶级窗口,默认使用BorderLayout管理其内部组件布局;Panel可以容纳其他组件&#xff0c;但不能独立存在&#xff0c;它必须内嵌其他容器中使用&#xff0c;默认使用FlowLayout管理其内部组件布局&#xff1b;S…

分布式文件系统 SpringBoot+FastDFS+Vue.js【二】

分布式文件系统 SpringBootFastDFSVue.js【二】 六、实现上传功能并展示数据6.1.创建数据库6.2.创建spring boot项目fastDFS-java6.3.引入依赖6.3.fastdfs-client配置文件6.4.跨域配置GlobalCrosConfig.java6.5.创建模型--实体类6.5.1.FastDfsFile.java6.5.2.FastDfsFileType.j…

leetcode:343.整数拆分

解题思路&#xff1a; 拆分的越多越好&#xff08;暂且认为&#xff09;&#xff0c;尽可能拆成m个近似相等的数&#xff0c;会使得乘积最大 dp含义&#xff1a;将i进行拆分得到最大的积为dp[i] 递推公式&#xff1a;j x dp[i-j](固定j&#xff0c;只通过凑dp[i-j]进而实现所…

Java学习第十四节之冒泡排序

冒泡排序 package array;import java.util.Arrays;//冒泡排序 //1.比较数组中&#xff0c;两个相邻的元素&#xff0c;如果第一个数比第二个数大&#xff0c;我们就交换他们的位置 //2.每一次比较&#xff0c;都会产生出一个最大&#xff0c;或者最小的数字 //3.下一轮则可以少…

寒假 6

1.现有无序序列数组为{23,24,12,5,33,5,34,7}&#xff0c;请使用以下排序实现编程。 函数1:请使用冒泡排序实现升序排序 函数2︰请使用简单选择排序实现升序排序 函数3:请使用直接插入排序实现升序排序 函数4∶请使用插入排序实现升序排序 #include <stdio.h> #inclu…

找负环(图论基础)

文章目录 负环spfa找负环方法一方法二实际效果 负环 环内路径上的权值和为负。 spfa找负环 两种基本的方法 统计每一个点的入队次数&#xff0c;如果一个点入队了n次&#xff0c;则说明存在负环统计当前每个点中的最短路中所包含的边数&#xff0c;如果当前某个点的最短路所…

Visual Studio Code连接远程MS Azure服务器的方法

1. 开启远程MS Azure服务器 Step 1.1. 登录MS Azure账号&#xff0c;https://azure.microsoft.com/en-us/get-started/azure-portal Step 1.2. 开启远程MS Azure服务器 2. 通过Visual Studio Code连接MS Azure远程服务器 Step 2.1. 安装Remote-SSH Extension Step 2.2. 选择…