Linux下IPC方式之共享存储映射(mmap)
Linux下IPC方式之共享存储映射(mmap)
- 1. 共享存储映射(mmap)
- 2. mmap九问
- 3. mmap实现父子进程通信
- 4. 匿名映射
- 5. mmap实现无血缘进程通信
1. 共享存储映射(mmap)
把文件中的某一段映射到内存上
mmap函数原型:
#include <sys/mman.h>
void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);
参数:
addr 建立映射区的首地址,由Linux内核指定。使用时,直接传递NULLlength 映射区长度prot
PROT_READ 可读
PROT_WRITE 可写flags
MAP_SHARED 共享的,对内存的修改会影响到源文件
MAP_PRIVATE 私有的fd 文件描述符offset 偏移量返回值
成功 返回 可用内存的首地址
失败 返回 MAP_FAILED
释放内存区
#include <sys/mman.h>
int munmap(void *addr, size_t length);
addr 传mmap返回值length mmap创建的长度返回值
成功:0; 失败:-1
实例(MAP_SHARED的作用是,你修改了内存,会影响文件)
#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<sys/mman.h>
#include<string.h>int main(){int fd=open("men.txt", O_RDWR);//创建映射区char *mem=(char*)mmap(NULL, 8, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);if(mem==MAP_FAILED){perror("mmap err");return -1;}//拷贝数据strcpy(mem, "hello");//释放mmapmunmap(mem, 8);close(fd);return 0;
}
2. mmap九问
- 如果更改mem变量的地址,释放的时候munmap,传入mem还能成功吗?
- 如果对mem越界操作会怎样?
- 如果文件偏移量随便填个数会怎样?
- 如果文件描述符先关闭,对mmap映射有没有什么影响?
- open的时候,可以新创建一个文件来创建映射区吗?
- open文件选择O_WRONLY,可以吗?
- 当选择MAP_SHARED的时候,open文件选择O_RDONLY,prot可以选择PROT_READ|PROT_WRITE吗?
- mmap什么情况下会报错?
- 如果不判断返回值会怎么样?
1.如果更改mem变量的地址,释放的时候munmap,传入mem还能成功吗?
问题一的测试:(不能改,否则会释放失败)
#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<sys/mman.h>
#include<string.h>int main(){int fd=open("men.txt", O_RDWR);//创建映射区char *mem=mmap(NULL, 8, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);if(mem==MAP_FAILED){perror("mmap err");return -1;}//拷贝数据strcpy(mem, "hello");mem++;//如果释放失败if (munmmap(mem, 8) < 0) {perror("munmmap err");}close(fd);return 0;
}
运行结果:
2.如果对mem越界操作会怎样?
问题二的测试:
#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<sys/mman.h>
#include<string.h>int main(){int fd=open("men.txt", O_RDWR);//创建映射区char *mem=mmap(NULL, 8, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);if(mem==MAP_FAILED){perror("mmap err");return -1;}//拷贝数据strcpy(mem, "hellollllllllllll");//释放内存munmmap(mem, 8);close(fd);return 0;
}
文件的大小对映射区操作有影响,尽量避免。
3.如果文件偏移量随便填个数会怎样?
char *mem=mmap(NULL, 8, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 1000000000);
offset必须是4k的整数倍。
4.如果文件描述符先关闭,对mmap映射有没有什么影响?
没有。因为mmap之后,通道就打通了,文件就没用了。
5.open的时候,可以新创建一个文件来创建映射区吗?
int fd=open("men.txt", O_RDWR|O_TRUNC, 0664);//创建并截断文件
如果新创建的文件是空的,会报错。
如果文件大小不为0,则可以。
6.open文件选择O_WRONLY,可以吗?
不可以,映射到内存的时候隐含一次读操作,如果只有写权限,则会报错
7.当选择MAP_SHARED的时候,open文件选择O_RDONLY,prot可以选择PROT_READ|PROT_WRITE吗?
不可以。SHARED的时候,映射区的权限要小于等于open文件的权限。
3. mmap实现父子进程通信
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <sys/wait.h>int main()
{// 先创建映射区int fd = open("mem.txt",O_RDWR);int *mem = mmap(NULL,4,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);//int *mem = mmap(NULL,4,PROT_READ|PROT_WRITE,MAP_PRIVATE,fd,0);if(mem == MAP_FAILED){perror("mmap err");return -1;}// fork子进程pid_t pid = fork();// 父进程和子进程交替修改数据if(pid == 0 ){//son *mem = 100;printf("child,*mem = %d\n",*mem);sleep(3);printf("child,*mem = %d\n",*mem);}else if(pid > 0){//parentsleep(1);printf("parent,*mem=%d\n",*mem);*mem = 1001;printf("parent,*mem=%d\n",*mem);//回收子进程wait(NULL);}//释放内存munmap(mem,4);close(fd);return 0;
}
运行结果
将上面的注释去掉,改成
//int *mem = mmap(NULL,4,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);
int *mem = mmap(NULL,4,PROT_READ|PROT_WRITE,MAP_PRIVATE,fd,0);
运行结果
父进程并没有读到子进程的数据,子进程也没有读到父进程改的数据。
如果要实现父子进程之间通信,需要将flags设为MAP_PRIVATE
4. 匿名映射
避免打开文件的操作(上面的例子都有调用open函数)
int *mem = mmap(NULL,4,PROT_READ|PROT_WRITE,MAP_SHARED|MAP_ANON,-1,0);
使用示例
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <sys/wait.h>int main()
{int *mem = mmap(NULL,4,PROT_READ|PROT_WRITE,MAP_SHARED|MAP_ANON,-1,0);if(mem == MAP_FAILED){perror("mmap err");return -1;}pid_t pid = fork();if(pid == 0 ){//son *mem = 101;printf("child,*mem=%d\n",*mem);sleep(3);printf("child,*mem=%d\n",*mem);}else if(pid > 0){//parent sleep(1);printf("parent,*mem=%d\n",*mem);*mem = 10001;printf("parent,*mem=%d\n",*mem);wait(NULL);}munmap(mem,4);return 0;
}
运行结果
注意:有的Unix系统中没有MAP_ANON,ANONYMOUS这两个宏。此时该怎么办?
此时用这个
/dev/zero
是一个聚宝盆,无限大,用它做匿名映射,你想取多大都可以。
另外一个,/dev/null
是一个无底洞,一般错误信息重定向到这个文件中
小技巧——快速把一个文件头几行的数据重定向到另一个文件中(会覆盖目标文件)
5. mmap实现无血缘进程通信
写端
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <sys/wait.h>typedef struct _Student{int sid;char sname[20];
}Student;int main(int argc,char *argv[])
{if(argc != 2){printf("./a.out filename\n");return -1;}// 1. open file int fd = open(argv[1],O_RDWR|O_CREAT|O_TRUNC,0666);//结构体的大小int length = sizeof(Student);//将文件大小改变为参数length指定的大小,//如果原来的文件大小比参数length大,则超过的部分会被删除,//如果原来的文件大小比参数length小,则文件将被扩展ftruncate(fd,length);// 2. mmapStudent * stu = mmap(NULL,length,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);//如果不判断是否出错,会死的很难看if(stu == MAP_FAILED){perror("mmap err");return -1;}int num = 1;// 3. 修改内存数据while(1){stu->sid = num;sprintf(stu->sname,"xiaoming-%03d",num++);sleep(1);//相当于每隔1s修改一次映射区的内容}// 4. 释放映射区和关闭文件描述符munmap(stu,length);close(fd);return 0;
}
读端
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <sys/wait.h>typedef struct _Student{int sid;char sname[20];
}Student;int main(int argc,char *argv[])
{//open file int fd = open(argv[1],O_RDWR);//mmap int length = sizeof(Student);Student *stu = mmap(NULL,length,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);if(stu == MAP_FAILED){perror("mmap err");return -1;}//read data while(1){printf("sid=%d,sname=%s\n",stu->sid,stu->sname);sleep(1);}//close and munmap munmap(stu,length);close(fd);return 0;
}
运行结果:
再开一个读的:
Linux下IPC方式之共享存储映射(mmap)相关推荐
- Linux系统编程---5(共享存储映射,存储映射I/O,mmap函数,父子进程间通信,匿名映射)
共享存储映射 文件进程间通信 使用文件也可以完成 IPC,理论依据是,fork 后,父子进程共享文件描述符.也就共享打开的文件. 编程:父子进程共享打开的文件.借助文件进行进程间通信. 测试代码 /* ...
- Linux下通过iscsi搭建共享存储
很多情况下,为了简单,我们经常简单的通过nfs来搭建共享存储服务. 有时候,一些软件需要,对共享存储有特殊要求,比如需要通过多个硬盘实现较大的存储空间,或者软件有特殊需要.这时,我们可以考虑通过isc ...
- Linux下进程间通信方式之管道、信号、共享内存、消息队列、信号量、套接字
/* 1,进程间通信 (IPC ) Inter-Process Communication比较好理解概念的就是进程间通信就是在不同进程之间传播或交换信息.2,linux下IPC机制的分类:管道.信号. ...
- 【Linux进程间通信】四、mmap共享存储映射
欢迎加入[Linux C/C++/Python社区]一起探讨和分享Linux C/C++/Python/Shell编程.机器人技术.机器学习.机器视觉.嵌入式AI相关领域的知识和技术. mmap共享存 ...
- Linux系统搭建NFS网络共享存储
Linux系统搭建NFS网络共享存储 一.NFS概述: NFS是一种基于TCP/IP传输的网络文件系统协议,最初由SUN公司开发.通过NFS协议,客户机可以像访问本地目录一样访问远程服务器中的共享资源 ...
- linux下rpm方式安装mysql(2012-5-12)
由于感觉前几篇博客中关于linux下rpm方式安装mysql的方法问题太多,今天抽时间重新实践和整理了一下,现在拿出来和大家分享,希望对家有用. 系统环境: Rat had enterprise li ...
- linux下Yum方式安装gcc
linux下Yum方式安装gcc学习记录 从CentOS7的系统安装镜像中取出需要的rpm包(也可以通过别的方式获取):解压镜像文件,进入"Packages"目录,里面很多rpm包 ...
- 【Linux下挂载QNAP NFS 共享权限异常处理】
Linux下挂载QNAP NFS 共享权限异常处理 前言 現象 處理 相關命令 NFS 配置中的權限壓縮 前言 在Linux 上掛載QNAP的NFS共享且啟用ACL可能會遇到ROOT用戶正常,但非RO ...
- linux操作系统进程间通信IPC之共享存储映射
(1)文件存储映射I/O(Memory-mapped I/O) 一个磁盘文件与存储空间中的一个缓存区相对应,这样可以在不适合read/write函数的情况下,使用地址(指针)完成I/O操作.具体实现通 ...
最新文章
- thrift使用小记_CUDev-ChinaUnix博客
- 华为:N个同学站成一排,发饼干至少每人一个,相邻分值高的可以多分一个以上饼干,求问至少需要发多少个饼干满足要求
- 设置图片圆角 或者圆形
- hdu 2570 贪心
- 服务器系统bsd,BSD操作系统大盘点:其它BSD变体
- python 写入csv 文件显示乱码_python 写入csv乱码问题解决方法
- 小书匠编辑器使用手册
- arm9 adc及触摸屏
- ASD: Average Surface Distance
- bzoj2286 消耗战 虚树树形dp
- 记一次网站服务器搬迁实录
- 2019税改有哪些变化?什么是专项扣除?这些改动与你的工资息息相关!
- 全球回报最好的 40 个 VC 投资案例,我们可以从中学到什么?
- 《圈外课程学习记录》1.1结构化的特征 1.2表达时主题先行
- KISSY基础篇乄目录
- Java正则表达式校验邮箱和手机号
- java 运动的大球吃小球_JAVA 多线程制作大球吃小球 一、实现球的自动生成及运动 生产消费模型...
- 公司寄件报销难?你缺的只是高效的寄件管理解决方案
- python3+ffmpeg下载B站视频,附代码
- 计算机毕业设计ssm人工智能辅修专业教学管理系统9xg0x系统+程序+源码+lw+远程部署
热门文章
- 电脑系统时间同步问题处理
- tensorflow详细安装教程(Win10, Anaconda,Python3.9)
- 怎样用python定位别人在哪_python程序员教你用微信给对方定位!你说回家!却还在外面鬼混?...
- JavaScript常用的字符串操作对象方法
- QBitArray 和 QByteArray 互相转换
- 2022低压电工考题及答案
- 亲属计算规则算法--js实现(关键算法摘要)
- 中基鸿业什么是净值型理财产品
- 火狐Firefox地址栏搜索引擎修改方法!
- 网站域名服务器加密,网站域名利用https防劫持方法