进程间通信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接收以下同步信号…

如何将本地项目上传到gitlab

具体步骤如下&#xff1a; 1. 登录 gitLab账号&#xff0c;成功创建一个项目文件&#xff0c;生成对应的http/https地址 2.打开本地项目&#xff0c;初始化git $ git init 3.将本地git和服务器上的连接&#xff08;确保项目没有其他远程连接的服务器端口&#xff09; $ gi…

MySQL Workbench下载安装、 MySQL Workbench使用

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

C#基础总结

这里写目录标题 目录1. 什么情况下需要override Equals?2. 什么时候需要override GetHashCode&#xff1f;3. int和int?有什么关系&#xff1f;两个类型转换是否涉及装箱过程&#xff1f;4. String类和StringBuiler类有什么区别&#xff1f;5. 抽象类和接口有什么区别&#x…

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

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

基于微信小程序的房屋租赁管理系统

介绍 基于微信小程序房屋租赁管理系统&#xff0c;对房东-房屋-房间-租客进行网格化管理&#xff0c;帮助政府部门统计分析所辖区域的出租房屋情况。 微信小程序可以视为一种新形态的应用。相比于已有的嵌入在浏览器中的HTML5网页应用&#xff0c;他具有更高的系统权限&#x…

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

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

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

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

Rust入门-Hello World

1、安装 在 Linux 或 macOS 上安装 rustup 打开终端并输入下面命令&#xff1a; $ curl --proto https --tlsv1.2 https://sh.rustup.rs -sSf | sh如果安装成功&#xff0c;将出现下面这行&#xff1a; Rust is installed now. Great!2、更新 $ rustup self uninstall3、卸…

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

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

红黑树(Red-Black Tree)

红黑树&#xff08;Red-Black Tree&#xff09;是一种自平衡的二叉查找树&#xff0c;它具有以下特性&#xff1a; 1. 每个节点要么是红色&#xff0c;要么是黑色。 2. 根节点是黑色的。 3. 每个叶子节点&#xff08;NIL节点&#xff09;是黑色的。 4. 如果一个节点是红色的&am…

手把手教你实现贪吃蛇

前言 在实现贪吃蛇前&#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;获取…

服务器有哪些特性?

服务器是计算机的一种&#xff0c;但是和普通的计算机是不同的&#xff0c;服务器比普通计算机的运行速度更快、负载能力更高&#xff0c;可以在网络中为其它客户机或是大型设备提供计算或者是应用服务&#xff0c;服务器有着高速的CPU运算能力、能够进行长时间的运行有着更好的…