进程间通信IPC(二)

一、存储映射I/O(Memory-mapped I/O)

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

mmap函数 

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

munmap函数

int munmap(void *addr, size_t length);

释放映射区。

addr:mmap 的返回值

length:大小

使用mmap创建一个映射区(共享内存),并往映射区里写入内容: 

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<errno.h>
#include<pthread.h>
#include<sys/mman.h>
#include<fcntl.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\n");//写操作printf("---%s\n",p);int ret = munmap(p,len);if (ret == -1){sys_err("munmap error");}return 0;
}

输出为:

---hello mmap

mmap使用注意事项 

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文件时,有读权限,用于创建映射区即可。

mmap函数的保险调用方式:

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

mmap总结

  1. 创建映射区的过程中,隐含着一次对映射文件的【读操作】
  2. 当MAP_SHARED时,要求:映射区的权限应该<=文件打开的权限(出于对映射区的保护)。而MAP_PRIVATE则无所谓,因为mmap中的权限是对内存的限制
  3. 映射区的释放与文件关闭无关。只要映射建立成功,文件可以立即关闭
  4. 特别注意,当映射文件大小为0时,不能创建映射区。所以:用于映射的文件必须要有实际大小!!mmap使用时常常会出现总线错误,通常是由于共享文件存储空间大小引起的。如,400字节大小的文件,在简历映射区时,offset4096字节,则会报出总线错误
  5. munmap传入的地址一定是mmap返回的地址。坚决【杜绝指针++】操作
  6. 文件偏移量必须为4K的整数倍
  7. mmap创建映射区出错概率非常高,一定要检查返回值,确保映射区建立成功再进行后续操作。

二、父子(由血缘关系)        进程间mmap通信

父子进程使用 mmap 进程间通信,要求如下:

1. 父进程先创建映射区。 open(O_RDWR) mmap(MAP_SHARED);
2. 指定MAP_SHARED权限
3. fork() 创建子进程。
4. 一个进程读, 另外一个进程写

父子进程mmap通信,对比全局变量 :

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/wait.h>int var = 100;
int main(void)
{int *p;pid_t pid;int fd;fd = open("temp",O_RDWR|O_CREAT|O_TRUNC,0644);if (fd < 0){perror("open error");exit(1);}ftruncate(fd,4);p = (int *)mmap(NULL,4,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 == NULL  {perror("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;
}

 将以上代码写入fork_mmap.c文件中,执行代码输出为:

child, *p = 7000, var = 1000
parent, *p = 7000, var = 100

子进程修改p的值,也反映到了父进程上,这是因为共享内存定义为shared的(读时共享,写时复制)

如果将共享内存定义为private,输出结果如下:

child, *p = 7000, var = 1000
parent, *p = 0, var = 100

改为私有之后,映射区归父进程私有,父子进程通信中断

三、无血缘关系进程间mmap通信

要求:

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

        2. 指定flags 为 MAP_SHARED。

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

注意:无血缘关系进程间mmap通信

mmap:

  • 数据可以重复读取。内容被读走之后不会消失,
  • 如果读进程的读取时间间隔短,它会读到很多重复内容,因为写进程没来得及写入新内容。数据只能一次读取

fifo:

  • 数据只能一次读取

以下是两个无血缘关系的通信代码,先是写进程:

写入时直接使用memcpy函数:参数一是指针,参数二是数据,参数三是字节数

#include<stdio.h>
#include<stdlib.h>
#include<fcntl.h>
#include<sys/mman.h>
#include<string.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);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(1);}       munmap(p,sizeof(stu));return 0;
}

然后是读进程:

#include<stdio.h>
#include<stdlib.h>
#include<fcntl.h>
#include<sys/mman.h>
#include<string.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",p->id,p->name,p->age);sleep(1);}       munmap(p,sizeof(stu));return 0;
}

运行阶段:

make mmap_w

make mmap_r

./mmap_w

另外一个终端执行:

./mmap_r

多个写端一个读端也是可以的,打开多个写进程之后读进程会读到所有写进程写入的内容。

*四、mmap匿名映射区

通过使用我们发现,使用映射区来完成文件读写操作十分方便,父子进程间通信也较容易。但缺陷是,每次创建映射区一定要依赖一个文件才能实现。可以直接使用匿名映射来代替。

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

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

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

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

相关文章

由于找不到msvcp110d.dll,无法继续执行代码

在计算机软件开发和运行环境中&#xff0c;动态链接库&#xff08;DLL&#xff09;文件扮演着至关重要的角色。它们封装了特定功能的代码&#xff0c;使得多个应用程序能够共享这些功能而无需重复编译或加载相同的代码&#xff0c;从而显著提升了系统资源利用率和软件开发效率。…

024——驱动、server、client、GUI全功能联调

目录 一、本次修改 二、GUI和Client之间联调 2.1 工程结构修改 2.2 将TCP程序修改为可被其它程序调用 2.3 优化显示界面 2.4 解决GUI通过tcp send的问题 2.5 处理服务器数据 时间不是很多了&#xff0c;我想压缩一下快点把属于毕设的这部分搞完&#xff0c;俺要出去旅游…

【HTML】H5新增元素记录

H5 新增元素特性 1. 语义化标签 语义化标签的好处&#xff1a; 对于浏览器来说&#xff0c;标签不够语义化对于搜索引擎来说&#xff0c;不利于SEO的优化 语义化标签&#xff1a; header:头部元素nav&#xff1a;导航section:定义文档某个区域的元素article:内容元素aside…

解锁多智能体路径规划新境界:结合启发式搜索提升ML本地策略

引言&#xff1a;多智能体路径寻找&#xff08;MAPF&#xff09;问题的重要性与挑战 在现代自动化和机器人技术迅速发展的背景下&#xff0c;多智能体路径寻找&#xff08;Multi-agent path finding&#xff0c;简称MAPF&#xff09;问题的研究变得日益重要。MAPF问题涉及为一…

【NTN 卫星通信】NTN的SSB波束探讨

1 概述 SSB是同步广播信道&#xff0c;用于小区搜索&#xff0c;主系统消息的发送。NR协议中定义了多种SSB波束格式&#xff0c;简述如下。   小区搜索是终端获取与小区的时间和频率同步并检测小区的物理层小区ID的过程。   为了进行小区搜索&#xff0c;UE接收以下同步信号…

MySQL Workbench下载安装、 MySQL Workbench使用

官方下载链接;MySQL :: Download MySQL Workbench 下载好懒人安装&#xff0c;也可自己选择目录 下面是使用&#xff1a; 连接数据库&#xff1a; 填写数据库连接信息&#xff1a; 基本操作部分&#xff1a; 数据导入导出&#xff1a; 导出/备份 导入&#xff1a; 生产er图…

【热门话题】探索与心得:深入体验Microsoft Edge浏览器

&#x1f308;个人主页: 鑫宝Code &#x1f525;热门专栏: 闲话杂谈&#xff5c; 炫酷HTML | JavaScript基础 ​&#x1f4ab;个人格言: "如无必要&#xff0c;勿增实体" 文章目录 探索与心得&#xff1a;深入体验Microsoft Edge浏览器一、Edge浏览器概述1.1 发…

大型网站系统架构演化实例_5.使用反向代理和CDN加速网站响应

1.使用反向代理和CDN加速网站响应 随着网站业务不断发展&#xff0c;用户规模越来越大&#xff0c;由于区域的差别使得网络环境异常复杂&#xff0c;不同地区的用户访问网站时&#xff0c;速度差别也极大。有研究表明&#xff0c;网站访问延迟和用户流失率正相关&#xff0c;网…

【嵌入式】交叉编译指南:将开源软件带到嵌入式世界

&#x1f9d1; 作者简介&#xff1a;阿里巴巴嵌入式技术专家&#xff0c;深耕嵌入式人工智能领域&#xff0c;具备多年的嵌入式硬件产品研发管理经验。 &#x1f4d2; 博客介绍&#xff1a;分享嵌入式开发领域的相关知识、经验、思考和感悟,欢迎关注。提供嵌入式方向的学习指导…

mybatis一对一,多对一,一对多--使用自动映射避免繁琐的resultMap

头疼的一对一&#xff0c;多对一&#xff0c;一对多写法 我们知道&#xff0c;相比较hibernate,mybatis的一对一&#xff0c;一对多都比较繁琐&#xff0c;hibernate可以直接在实体类里面配置好映射关系&#xff0c;获取值的时候就能把一对一和一对多的对象带出来了&#xff0…

手把手教你实现贪吃蛇

前言 在实现贪吃蛇前&#xff0c;我们需要熟练地掌握C语言知识&#xff0c;对初阶数据结构中的链表有一定的掌握&#xff0c;并且我们还会使用到Win 32 API 的知识&#xff0c;下面我会对需要使用到的API接口函数进行解释。最终的代码我放在后面&#xff0c;有需要的可以自取。…

探索C语言数据结构:利用顺序表完成通讯录的实现

在好久之前我就已经学习过顺序表&#xff0c;但是在前几天再次温习顺序表的时候&#xff0c;我惊奇的发现顺序编表可以完成我们日常使用的通讯录的功能&#xff0c;那么今天就来好好通过博客总结一下通讯录如何完成吧。 常常会回顾努力的自己&#xff0c;所以要给自己的努力留…

OpenHarmony其他工具类—lua

简介 Lua是一种功能强大、高效、轻量级、可嵌入的脚本语言。 支持过程编程、面向对象编程、函数编程、数据驱动编程和数据描述。 下载安装 直接在OpenHarmony-SIG仓中搜索lua并下载。 使用说明 以OpenHarmony 3.1 Beta的rk3568版本为例 将下载的lua库代码存在以下路径&#…

Java Web3-2 - tomcat

https://github.com/heibaiying/Full-Stack-Notes/blob/master/notes/Tomcat_架构解析.md https://zhuanlan.zhihu.com/p/40249834 早期&#xff0c;web技术主要用于浏览静态页面 时间发展&#xff0c;用户已经不满足于仅浏览静态页面。用户需要一些交互操作&#xff0c;获取…

STM32G431RBT6之时钟树配置与生成工程

默认大家都下载了蓝桥杯嵌入式资源包了哈. 首先,打开cubumx,修改RCC与SYS. 打开并观察原理图,发现晶振是24Mhz. 第一步,打开Clock Configuration. 第二步,修改晶振为原理图相对应的24Mhz. 第三步,切换到HSE. 第四步,切换到PLLCLK. 第五步,设置HCLK为80Mhz(15届真题要求为8…

洛谷P1057 [NOIP2008 普及组] 传球游戏

#include<iostream> using namespace std; int n;// n个人传球游戏 默认开始球在编号为1的位置 int m;// 传递m次球 int main(){cin>>n>>m;// 动态转方程&#xff1a;// 球传递到编号为k人的手中// 种类总数 传递到k-1编号种类总数 传递到k1编号种类总数//…

wsl2 Ubuntu子系统内存只有一半的解决办法

物理机的内存是64G&#xff0c;在wsl2安装完Ubuntu20.04后&#xff0c;输入命令&#xff1a; free -g 发现只有32G&#xff0c;原因是默认只能获得物理机一半的内存&#xff1a; WSL 中的高级设置配置 | Microsoft Learn 因此可手动修改为与物理机同等大小&#xff1a; 1&a…

再拓信创版图-Smartbi Insight V11与东方国信CirroData数据库完成兼容适配认证

近日&#xff0c;思迈特商业智能与数据分析软件 [简称&#xff1a;Smartbi Insight] V11与北京东方国信科技股份有限公司 &#xff08;以下简称东方国信&#xff09;CirroData-OLAP分布式数据库V2.14.1完成兼容性测试。经双方严格测试&#xff0c;两款产品能够达到通用兼容性要…

Cronjob提权

参考&#xff1a; https://redpomelo.xyz/archives/1699953656909 前言 提权为该靶机的精髓&#xff0c;Cronjob通常以root特权运行。如果我们可以成功篡改cronjob中 定义的任何脚本或二进制文件&#xff0c;那么我们可以以root特权执行任意 代码。 什么是Cronjob&#xf…

Jmeter 性能-死锁问题定位+分析

1、环境搭建 ①准备脚本&#xff0c;执行压测 ②用Jstack 打印日志 jstack 112759 >dead.log ③下载日志到本地 sz dead.log 2、问题定位 ①打开dead.log&#xff0c;搜索deadlock ②查看死锁的线程 ③查看死锁位置 3、问题分析 ①下载死锁的类文件 Sz CaseControlle…