成功的门户网站,中国导航电子地图,中国建设银行网站用户名是什么,运营公开网是什么网站5.共享映射区#xff08;无血缘关系用的#xff09; 文章目录 5.共享映射区#xff08;无血缘关系用的#xff09;1.概述2.mmapmunmap函数3.mmap注意事项4.mmap实现进程通信父子进程练习 无血缘关系 5.mmap匿名映射区 1.概述 原理#xff1a;共享映射区是将文件…5.共享映射区无血缘关系用的 文章目录 5.共享映射区无血缘关系用的1.概述2.mmapmunmap函数3.mmap注意事项4.mmap实现进程通信父子进程练习 无血缘关系 5.mmap匿名映射区 1.概述 原理共享映射区是将文件内容映射到进程的地址空间中使得多个进程可以通过访问这个共享的内存区域来实现通信。进程对映射区域的操作就如同对文件进行操作一样这些操作会直接反映在文件和其他共享该映射区域的进程中。 示例场景多个进程需要共同操作一个配置文件通过将该配置文件映射到共享映射区进程可以直接在内存中读取和修改配置信息而不需要频繁地进行文件 I/O 操作。 优点结合了内存操作的高效性和文件存储的持久性可以方便地在不相关的进程之间实现通信只要它们能访问到同一个文件。 缺点对文件的操作需要注意同步问题否则可能导致数据不一致文件大小可能会限制共享映射区的大小。
**存储映射I/O(Memory-mapped l/O)使一个磁盘文件与内存存储空间中的一个缓冲区相映射。**于是当从缓冲区中取数据,就相当于读文件中的相应字节。于此类似,将数据存入缓冲区,则相应的字节就自动写入文件。这样,就可在不适用read和write函数的情况下,使用地址(指针)完成I/O操作。
使用这种方法,首先应通知内核,将一个指定文件映射到存储区域中。这个映射工作可以通过mmap函数来实 现。
2.mmapmunmap函数
创建共享内存映射
includesys/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);参数
addrmmap 的返回值共享内存映射首地址
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.hvoid 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注意事项
思考 : 可以open的时候O_CREAT一个新文件来创建映射区吗 ? 如果open时O_RDONLY,mmap时PROT参数指定PROT_READ|PROT_WRITE会怎样 ? 文件描述符先关闭,对mmap映射有没有影响 ? 如果文件偏移量为1000会怎样 ? 对mem越界操作会怎样? 如果mem,munmap可否成功 ? mmap什么情况下会调用失败 ? 很多参数都会导致失败 如果不检测mmap的返回值,会怎样? 会死得很惨
使用注意事项
用于创建映射区的文件大小为 0却指定非0大小创建映射区出 “总线错误”。用于创建映射区的文件大小为 0也指定0大小创建映射区 出 “无效参数”。用于创建映射区的文件读写属性为只读映射区属性为 读、写。 出 “无效参数” 文件和映射区都是只读的是可以的文件只有写权限映射区只有写权限也会报错。2答案创建映射区需要read权限。当访问权限指定为 “共享”MAP_SHARED是 mmap的读写权限应该 文件的open权限。 映射区只写不行。文件描述符fd在mmap创建映射区完成即可关闭。后续访问文件用 地址访问。3答案offset 必须是 4096的整数倍。MMU 映射的最小单位 4k 4答案对申请的映射区内存不能越界访问。 5答案读写都没问题但是munmap会失败munmap用于释放的 地址必须是mmap申请返回的地址。6答案映射区访问权限为 “私有”MAP_PRIVATE, 对内存所做的所有修改只在内存有效不会反应到物理磁盘上。映射区访问权限为 “私有”MAP_PRIVATE, 只需要open文件时文件有读权限用于创建映射区即可。 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.hint 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.hstruct 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.hstruct 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要 | 下面提到的两个宏 /dev/zero 从这个文件里面拿数据可以随便拿想要多大拿多大的数据只不过读出来都是文件空洞