当前位置: 首页 > news >正文

进程通信方式---共享映射区(无血缘关系用的)

5.共享映射区(无血缘关系用的)

文章目录

    • 5.共享映射区(无血缘关系用的)
      • 1.概述
      • 2.mmap&&munmap函数
      • 3.mmap注意事项
      • 4.mmap实现进程通信
        • 父子进程
          • 练习
        • 无血缘关系
      • 5.mmap匿名映射区

1.概述

  • 原理:共享映射区是将文件内容映射到进程的地址空间中,使得多个进程可以通过访问这个共享的内存区域来实现通信。进程对映射区域的操作就如同对文件进行操作一样,这些操作会直接反映在文件和其他共享该映射区域的进程中。

  • 示例场景:多个进程需要共同操作一个配置文件,通过将该配置文件映射到共享映射区,进程可以直接在内存中读取和修改配置信息,而不需要频繁地进行文件 I/O 操作。

  • 优点:结合了内存操作的高效性和文件存储的持久性;可以方便地在不相关的进程之间实现通信,只要它们能访问到同一个文件。

  • 缺点:对文件的操作需要注意同步问题,否则可能导致数据不一致;文件大小可能会限制共享映射区的大小。

**存储映射I/O(Memory-mapped l/O)使一个磁盘文件与内存存储空间中的一个缓冲区相映射。**于是当从缓冲区中取数据,就相当于读文件中的相应字节。于此类似,将数据存入缓冲区,则相应的字节就自动写入文件。这样,就可在不适用read和write函数的情况下,使用地址(指针)完成I/O操作。

使用这种方法,首先应通知内核,将一个指定文件映射到存储区域中。这个映射工作可以通过mmap函数来实
现。

2.mmap&&munmap函数

创建共享内存映射

include<sys/mman.h>
void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);	

参数:

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

  • length:共享内存映射区的大小。(<= 文件的实际大小)

  • prot: 共享内存映射区的读写属性。PROT_READ、PROT_WRITE、PROT_READ|PROT_WRITE

  • flags: 标注共享内存的共享属性,共享就是对文件的修改会写回磁盘,私有就不会写回磁盘。MAP_SHARED、MAP_PRIVATE

  • fd: 用于创建共享内存映射区的那个文件的 文件描述符,就是要映射到内存的文件

  • offset:默认0,表示映射文件全部。偏移位置,从哪里开始映射。需是 4k 的整数倍

返回值:

成功:映射区的首地址

失败:MAP_FAILED (void*(-1)), errno----就是把-1强转为void *了

释放共享内存映射

int munmap(void *addr, size_t length);

参数

addr:mmap 的返回值,共享内存映射首地址

length:大小

返回值

成功0,失败-1

函数使用

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <pthread.h>void sys_err(const char *str)
{perror(str);exit(1);
}int main(int argc, char *argv[])
{char *p = NULL;int fd;fd = open("testmap", O_RDWR|O_CREAT|O_TRUNC, 0644);     // 创建文件用于创建映射区if (fd == -1)sys_err("open error");
/*lseek(fd, 10, SEEK_END);            // 两个函数等价于 ftruncate()函数write(fd, "\0", 1);
*/ftruncate(fd, 20);                  // 需要借助写权限,才能够对文件进行拓展int len = lseek(fd, 0, SEEK_END);p = mmap(NULL, len, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);if (p == MAP_FAILED) {sys_err("mmap error");}// 使用 p 对文件进行读写操作.strcpy(p, "hello mmap");            // 写操作printf("----%s\n", p);              // 读操作int ret = munmap(p, len);           // 释放映射区if (ret == -1) {sys_err("munmap error");}return 0;
}

3.mmap注意事项

思考 :

  1. 可以open的时候O_CREAT一个新文件来创建映射区吗 ?

  2. 如果open时O_RDONLY,mmap时PROT参数指定PROT_READ|PROT_WRITE会怎样 ?

  3. 文件描述符先关闭,对mmap映射有没有影响 ?

  4. 如果文件偏移量为1000会怎样 ?

  5. 对mem越界操作会怎样?

  6. 如果mem++,munmap可否成功 ?

  7. mmap什么情况下会调用失败 ?

    很多参数都会导致失败

  8. 如果不检测mmap的返回值,会怎样?

    会死得很惨

使用注意事项:

  1. 用于创建映射区的文件大小为 0,却指定非0大小创建映射区,出 “总线错误”。
  2. 用于创建映射区的文件大小为 0,也指定0大小创建映射区, 出 “无效参数”。
  3. 用于创建映射区的文件读写属性为,只读,映射区属性为 读、写。 出 “无效参数”; 文件和映射区都是只读的是可以的;文件只有写权限,映射区只有写权限也会报错。(2答案)
  4. 创建映射区,需要read权限。当访问权限指定为 “共享”MAP_SHARED是, mmap的读写权限应该 <=文件的open权限。 映射区只写不行。
  5. 文件描述符fd,在mmap创建映射区完成即可关闭。后续访问文件,用 地址访问。(3答案)
  6. offset 必须是 4096的整数倍。(MMU 映射的最小单位 4k )(4答案)
  7. 对申请的映射区内存,不能越界访问。 (5答案)
  8. 读写都没问题,但是munmap会失败,munmap用于释放的 地址,必须是mmap申请返回的地址。(6答案)
  9. 映射区访问权限为 “私有”MAP_PRIVATE, 对内存所做的所有修改,只在内存有效,不会反应到物理磁盘上。
  10. 映射区访问权限为 “私有”MAP_PRIVATE, 只需要open文件时,文件有读权限,用于创建映射区即可。

image-20241218222315367

mmap函数的保险调用方式:

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

4.mmap实现进程通信

父子进程

父子等有血缘关系的进程之间也可以通过mmap建立的映射区来完成数据通信。

但相应的要在创建映射区的时候指定对应的标志位参数flags:

MAP_PRIVATE:(私有映射)父子进程各自独占映射区;

MAP_SHARED:(共享映射) 父子进程共享映射区;

结论:

父子进程共享:1. 打开的文件 2.mmap建立的映射区(但必须要使用MAP_SHARED)

流程:

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

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

2.指定 MAP_SHARED 权限

3.fork() 创建子进程。

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

练习

练习:父进程创建映射区,然后fork子进程,子进程修改映射区内容,而后,父进程读取映射区内容,查验是
否共享

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/wait.h>int var = 100;int main(void)
{int *p;pid_t pid;int fd = open("temp", O_RDWR);//p = (int *)mmap(NULL, 40, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0);p = (int *)mmap(NULL, 490, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);//p = (int *)mmap(NULL, 4, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0); 私有的不行if(p == MAP_FAILED){		//注意:不是p == NULLperror("mmap error");exit(1);}close(fd);pid = fork();				//创建子进程if(pid == 0){*p = 7000;               // 写共享内存var = 1000;printf("child, *p = %d, var = %d\n", *p, var);} else {sleep(1);printf("parent, *p = %d, var = %d\n", *p, var);     // 读共享内存wait(NULL);int ret = munmap(p, 4);				//释放映射区if (ret == -1) {perror("munmap error");exit(1);}}return 0;
}
无血缘关系

流程: 【要求会写】

1.两个进程 打开同一个文件,创建映射区。

2.指定flags 为 MAP_SHARED。

3.一个进程写入,另外一个进程读出。

【注意】:无血缘关系进程间通信。

​ mmap:数据可以重复读取。

​ fifo:数据只能一次读取。

读端

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <unistd.h>
#include <errno.h>struct student {int id;char name[256];int age;
};void sys_err(const char *str)
{perror(str);exit(1);
}int main(int argc, char *argv[])
{struct student stu;struct student *p;int fd; fd = open("test_map", O_RDONLY);if (fd == -1)sys_err("open error");p = mmap(NULL, sizeof(stu), PROT_READ, MAP_SHARED, fd, 0);if (p == MAP_FAILED)sys_err("mmap error");close(fd);while (1) {printf("id= %d, name=%s, age=%d\n", p->id, p->name, p->age);usleep(10000);}munmap(p, sizeof(stu));return 0;
}

写端

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <unistd.h>
#include <errno.h>struct student {int id;char name[256];int age;
};void sys_err(const char *str)
{perror(str);exit(1);
}int main(int argc, char *argv[])
{struct student stu = {1, "xiaoming", 18};struct student *p;int fd; //    fd = open("test_map", O_RDWR|O_CREAT|O_TRUNC, 0664);fd = open("test_map", O_RDWR);if (fd == -1)sys_err("open error");ftruncate(fd, sizeof(stu));p = mmap(NULL, sizeof(stu), PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);if (p == MAP_FAILED)sys_err("mmap error");close(fd);while (1) {memcpy(p, &stu, sizeof(stu));stu.id++;sleep(2);}munmap(p, sizeof(stu));return 0;
}

5.mmap匿名映射区

匿名映射:只能用于 血缘关系(父子)进程间通信。

p = (int *)mmap(NULL, 40, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0);

映射区大小想要多少写多少

权限想要啥写啥

文件描述符的地方传-1

flags要 | 下面提到的两个宏

image-20241218224059685

/dev/zero 从这个文件里面拿数据可以随便拿,想要多大拿多大的数据,只不过读出来都是文件空洞

相关文章:

进程通信方式---共享映射区(无血缘关系用的)

5.共享映射区&#xff08;无血缘关系用的&#xff09; 文章目录 5.共享映射区&#xff08;无血缘关系用的&#xff09;1.概述2.mmap&&munmap函数3.mmap注意事项4.mmap实现进程通信父子进程练习 无血缘关系 5.mmap匿名映射区 1.概述 原理&#xff1a;共享映射区是将文件…...

深度学习实战智能交通计数

本文采用YOLOv8作为核心算法框架&#xff0c;结合PyQt5构建用户界面&#xff0c;使用Python3进行开发。YOLOv8以其高效的实时检测能力&#xff0c;在多个目标检测任务中展现出卓越性能。本研究针对车辆目标数据集进行训练和优化&#xff0c;该数据集包含丰富的车辆目标图像样本…...

【MySQL】MySQL表的操作

【MySQL】MySQL表的操作 &#x1f955;个人主页&#xff1a;开敲&#x1f349; &#x1f525;所属专栏&#xff1a;MySQL&#x1f34b; &#x1f33c;文章目录&#x1f33c; 1. 创建表 2. 查看表结构 3. 修改表 4. 删除表 1. 创建表 create table table_name(表名称)( fiel…...

Redis篇-12--数据结构篇4--Hash内存模型(数组,链表,压缩列表zipList,哈希表,短结构)

Redis的Hash数据结构用于存储键值对&#xff08;key-value形式&#xff09;的集合&#xff08;类似java中HashMap或对象&#xff09;。为了在保证高效性能的同时节省内存&#xff0c;Redis对Hash的底层实现进行了多种优化。特别是通过使用压缩列表&#xff08;ziplist&#xff…...

二、windows环境下vscode使用wsl教程

本篇文件介绍了在windows系统使用vscode如何连接使用wsl&#xff0c;方便wsl在vscode进行开发。 1、插件安装 双击桌面vscode&#xff0c;按快捷键CtrlShiftX打开插件市场&#xff0c;搜索【WSL】点击安装即可。 2、开启WSL的linux子系统 点击左下方图标【Open a Remote Win…...

Qwen2-VL微调体验

1.配置环境 2.数据集准备 3.模型下载 4.注册SwanLab 5.微调 6.训练过程可视化 1.配置环境 本博客使用的是2B模型&#xff0c;所以仅用了单卡3090&#xff0c;若大一点的模型&#xff0c;自行根据实际情况准备显卡 安装Python>3.8 安装Qwen2-VL必要的库 pip install…...

论文的模拟环境和实验环境

模拟环境和实验环境 在撰写SCI计算机领域论文时,模拟环境和实验环境是两个重要的概念,它们之间存在显著的差异。 模拟环境主要是利用计算机、数学方法等手段对实际系统进行描述和分析的过程。在计算机科学中,模拟环境可以用于模拟各种算法、系统或网络的行为,以便在不需要…...

MySQL EXPLAIN 详解:一眼看懂查询计划

在日常的数据库开发中&#xff0c;我们经常需要分析 SQL 查询性能&#xff0c;而 EXPLAIN 是 MySQL 提供的利器&#xff0c;可以帮我们快速理解查询计划&#xff0c;优化慢查询。本文将详细解析 EXPLAIN 的输出字段及其含义&#xff0c;并结合实际案例分享优化思路。 一、什么是…...

自动呼入机器人如何与人工客服进行无缝切换?

自动呼入机器人如何与人工客服进行无缝切换&#xff1f; 原作者&#xff1a;开源呼叫中心FreeIPCC&#xff0c;其Github&#xff1a;https://github.com/lihaiya/freeipcc 自动呼入机器人与人工客服的无缝切换详解 自动呼入机器人与人工客服之间的无缝切换是确保客户体验连续…...

二分类模型的性能评价指标

1. 混淆矩阵 (Confusion Matrix) 预测正类预测负类实际正类 (P)True Positive (TP)False Negative (FN)实际负类 (N)False Positive (FP)True Negative (TN) True Positive (TP): 模型正确预测为正类的样本数。True Negative (TN): 模型正确预测为负类的样本数。False Positi…...

鸿蒙操作系统简介

华为鸿蒙系统&#xff08;HUAWEI HarmonyOS&#xff09;&#xff0c;是华为公司于2019年8月9日在东莞举行的华为开发者大会&#xff08;HDC.2019&#xff09;上正式发布的面向全场景的分布式操作系统&#xff0c;可以创造一个超级虚拟终端互联的世界&#xff0c;将人、设备、场…...

单片机:实现蜂鸣器数码管的显示(附带源码)

单片机实现蜂鸣器数码管显示 蜂鸣器和数码管在嵌入式系统中广泛应用。蜂鸣器可以发出声音警告或提示&#xff0c;而数码管则用于显示数字或字母。在本项目中&#xff0c;我们将通过8051单片机实现一个控制蜂鸣器和数码管显示的系统&#xff0c;结合使用蜂鸣器和数码管&#xf…...

C语言期末复习笔记(上)

目录 一、为什么要学习C语言 1.C语言适合做什么 2.开发C程序的步骤 3.常用术语 二、C语言数据结构 1.常量与变量 &#xff08;1&#xff09;常量 ​编辑 &#xff08;2&#xff09;变量 2.数据类型 ​编辑 &#xff08;1&#xff09;数据类型的分类 &#xff08;2&a…...

HarmonyOS 实时监听与获取 Wi-Fi 信息

文章目录 摘要项目功能概述代码模块详细说明创建 Wi-Fi 状态保存对象Wi-Fi 状态监听模块获取当前 Wi-Fi 信息整合主模块 运行效果展示性能分析总结 摘要 本文展示了如何使用 HarmonyOS 框架开发一个 Demo&#xff0c;用于监听手机的 Wi-Fi 状态变化并实时获取连接的 Wi-Fi 信息…...

Unity超优质动态天气插件(含一年四季各种天气变化,可用于单机局域网VR)

效果展示&#xff1a;https://www.bilibili.com/video/BV1CkkcYHENf/?spm_id_from333.1387.homepage.video_card.click 在你的项目中设置enviro真的很容易&#xff01;导入包裹并按照以下步骤操作开始的步骤&#xff01; 1. 拖拽“EnviroSky”预制件&#xff08;“environme…...

1 JVM JDK JRE之间的区别以及使用字节码的好处

JDK jdk是编译java源文件成class文件的&#xff0c;我们使用javac命令把java源文件编译成class文件。 我们在java安装的目录下找到bin文件夹&#xff0c;如下图所示: 遵循着编译原理&#xff0c;把java源文件编译成JVM可识别的机器码。 其中还包括jar打包工具等。主要是针对…...

【网络安全】网站常见安全漏洞—服务端漏洞介绍

文章目录 网站常见安全漏洞—服务端漏洞介绍引言1. 第三方组件漏洞什么是第三方组件漏洞&#xff1f;如何防范&#xff1f; 2. SQL 注入什么是SQL注入&#xff1f;如何防范&#xff1f; 3. 命令执行漏洞什么是命令执行漏洞&#xff1f;如何防范&#xff1f; 4. 越权漏洞什么是越…...

MAPTR:在线矢量化高精地图构建的结构化建模与学习(2208)

MAPTR: STRUCTURED MODELING AND LEARNING FOR ONLINE VECTORIZED HD MAP CONSTRUCTION MAPTR&#xff1a;在线矢量化高精地图构建的结构化建模与学习 ABSTRACT High-definition (HD) map provides abundant and precise environmental information of the driving scene, se…...

基于容器的云原生,让业务更自由地翱翔云端

无论是要构建一个应用或开发一个更庞大的解决方案&#xff0c;在技术选型时&#xff0c;技术的开放性和可移植性已经成为很多企业优先考虑的问题之一。毕竟没人希望自己未来的发展方向和成长速度被自己若干年前选择使用的某项技术所限制或拖累。 那么当你的业务已经上云&#x…...

大屏开源项目go-view二次开发2----半环形控件(C#)

环境搭建参考&#xff1a; 大屏开源项目go-view二次开发1----环境搭建(C#)-CSDN博客 要做的半环形控件最终效果如下图&#xff1a; 步骤如下&#xff1a; 1 在go-view前端项目的\src\packages\components\Charts目录下新增Others目录&#xff0c;并在Others目录下新增PieExt…...

web:pc端企业微信登录-vue版

官方文档&#xff1a;developer.work.weixin.qq.com/document/pa… 不需要调用ww.register&#xff0c;直接调用ww.createWWLoginPanel即可创建企业微信登录面板 - 文档 - 企业微信开发者中心 (qq.com) 引入 //通过 npm 引入 npm install wecom/jssdk import * as ww from we…...

OpenGL ES 01 渲染一个四边形

项目架构 着色器封装 vertex #version 300 es // 接收顶点数据 layout (location 0) in vec3 aPos; // 位置变量的属性位置值为0 layout (location 1) in vec4 aColors; // 位置变量的属性位置值为1 out vec4 vertexColor; // 为片段着色器指定一个颜色输出void main() {gl…...

【ETCD】【源码阅读】深入解析 EtcdServer.applyEntries方法

applyEntries方法的主要作用是接收待应用的 Raft 日志条目&#xff0c;并按顺序将其应用到系统中&#xff1b;确保条目的索引连续&#xff0c;避免丢失或重复应用条目。 一、函数完整代码 func (s *EtcdServer) applyEntries(ep *etcdProgress, apply *apply) {if len(apply.…...

概率论得学习和整理28:用EXCEL画折线图,X轴数据也被当成曲线的解决办法

目录 1 折线图和散点图&#xff0c;对数据的处理差别 1.1 EXCEL画图的一些默认设置 1.2 多于2列的数据&#xff0c;也是如此 2 如果我们非要以第1列数据为X轴&#xff0c;做一个折线图呢&#xff1f;也能 2.1 首先&#xff0c;把第1列&#xff0c;想当成X轴的数据&#xf…...

tryhackme-Pre Security-Defensive Security Intro(防御安全简介)

任务一&#xff1a;Introduction to Defensive Security防御安全简介 此room的两个要点&#xff1a; Preventing intrusions from occurring 防止入侵发生Detecting intrusions when they occur and responding properly 检测发生的入侵并正确响应 防御安全还有更多内容。 除上…...

27. 元类

一、什么是元类 在 Python 中&#xff0c;一切皆为对象&#xff0c;即类也是一个对象。type 是内置的元类。我们用 class 关键字定义的所有的类以及内置的类都是由元类 type&#xff08;内置的元类&#xff09; 实例化产生的。 class Person:def __init__(self, name, age):se…...

PHP木马编写

一、最简单的一句话木马 <?php eval($_REQUEST[cmd]); ?> 1. <?php 和 ?> <?php 和 ?> 是 PHP 代码的开始和结束标记&#xff0c;表示 PHP 代码块的范围。 2. eval() eval() 是 PHP 中的一个内建函数&#xff0c;用来执行字符串类型的 PHP 代码。…...

游戏AI实现-寻路算法(Dijkstra)

戴克斯特拉算法&#xff08;英语&#xff1a;Dijkstras algorithm&#xff09;&#xff0c;又称迪杰斯特拉算法、Dijkstra算法&#xff0c;是由荷兰计算机科学家艾兹赫尔戴克斯特拉在1956年发现的算法。 算法过程&#xff1a; 1.首先设置开始节点的成本值为0&#xff0c;并将…...

Android OpenGLES2.0开发(九):图片滤镜

“当你改变想法的时候&#xff0c;记得也要改变你的世界。”——诺曼文森特皮尔 Android OpenGLES开发&#xff1a;EGL环境搭建Android OpenGLES2.0开发&#xff08;一&#xff09;&#xff1a;艰难的开始Android OpenGLES2.0开发&#xff08;二&#xff09;&#xff1a;环境搭…...

SQLite Update 语句

SQLite Update 语句 SQLite 的 UPDATE 语句用于更新数据库表中的现有记录。使用 UPDATE 语句&#xff0c;您可以修改一个或多个列的值。本教程将详细介绍如何使用 SQLite UPDATE 语句&#xff0c;包括语法、示例以及一些最佳实践。 语法 SQLite UPDATE 语句的基本语法如下&a…...