#include <sys/mman.h>
void *mmap(void *addr,size_t length,int prot,int flags,int fd,off_t offset);
int munmap(void *addr,size_t length);
-功能:将一个文件或者设备的数据映射到内存中
-参数:
-void *addr:NULL,由内核指定
-length:要映射的数据长度,这个值不能为0,建议使用文件的长度,获取文件的长度:stat lseek
-proc:对申请的内存映射区的操作权限
-PROT_EXEC:可执行的权限
-PROT_READ:读权限
-PROT_WRITE:写权限
-PROT_NONE:没有权限
要操作映射内存,必须要有读的权限。
PROT_READ 、PROT_READ|PROT_WRITE
-flags:
-MAP_SHARED:映射区的数据会自动和磁盘文件进行同步,进程间通信,必须要设置这个选项
-MAP_PRIVATE:不同步,内存映射区的数据改变了,对原来的文件
-fd:需要映射的那个文件的文件描述符
-通过open得到,open的是一个磁盘文件
-注意:文件的大小不能为0,open指定的权限不能和prot参数有冲突
prot:PROT_READ open 只读/读写
prot:PROT_READ |PROT_WRITE open:读写
-offset:偏移量,一般不用。必须指定4K的整数倍,0表示不偏移
-返回值:返回创建的内存首地址
失败返回MAP_FAILED,(void *) -1
int mumap(void *addr,size_t length);
-功能:释放内存映射
-参数:
-addr:要释放的内存的首地址
-length:要释放的内存大小,要和mmap函数中的length参数值一样
使用内存映射实现进程间通信:
1、有关系的进程(父子进程)
-还没有子进程的时候
-通过唯一的父进程,先创建内存映射区
-有了内存映射区以后,创建子进程
-父子进程共享创建的内存映射区
2、没有关系的进程间通信
-准备一个大小不是0的磁盘文件
-进程1 通过磁盘文件创建内存映射区
-得到一个操作这块内存的指针
-进程2 通过磁盘文件创建内存映射区
-得到一个操作这块内存的指针
-使用内存映射区通信
注意:内存映射区通信,是非阻塞
首先我们写一个有父子关系的内存映射
这里需要注意的点:一定要提前创建一个映射区,例如test.txt,并且这个映射区的大小必须大于0,否则没有办法往里面添加数据。(创建完之后可以在test.txt里写上几个字来扩充其大小。)
1 #include <stdio.h>
2 #include <wait.h>
3 #include <sys/mman.h>
4 #include <unistd.h>
5 #include <stdlib.h>
6 #include <sys/stat.h>
7 #include <sys/types.h>
8 #include <fcntl.h>
9 #include <string.h>
10 int main()
11 {
12 int fd=open("test.txt",O_RDWR);//1、打开一个文件
13 int size=lseek(fd,0,SEEK_END);//2、获取文件的大小,从fd这个文件的起始位置到文件末尾
14 void *ptr=mmap(NULL,size,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);//3、一定要在创建父子进程之前创建内存映射区
15 if(ptr==MAP_FAILED)//如果出现错误,类似于其他函数返回-1
16 {
17 perror("mmap");
18 exit(0);
19 }
20 //4、创建子进程
21 pid_t pid=fork();
22 if(pid>0)
23 {
24 wait(NULL);//回收子进程
//父进程
25 char buf[64];
26 strcpy(buf,(char *)ptr);//将ptr中的数据复制到buf中
27 printf("read data:%s\n",buf);
28
29 }
30 else if(pid==0)
31 { //子进程
32 strcpy((char *)ptr,"你好呀,小朋友!");
33 }
34 munmap(ptr,size);//将前面创建的内存映射区解除掉
35 return 0;
36 }
输出结果为:
补充:如果想把“读”和“写”分开操作也是可以的,这正好是没有关系的进程间通信,其实是非常简单的,只要把本程序中的父子进程分别写到两个文件中就可以了,这个我就不操作了,可以留作课下作业去完成。
还有,你写到两个文件中后,本程序中的前三步依然是要有的,切记!
另外,内存映射还有几点注意事项:
(1)如果对mmap的返回值(ptr)做++操作(ptr++),munmap是否能够成功?
void *ptr=mmap();
ptr++;//可以对其将进行++操作
munmap(ptr,len)//错误,要保存地址,释放的应该是源地址,而源地址已经发生了变化
(2)如果open时O_RDONLY,mmap时prot参数指定PROT_READ | PROT_WRITE会怎么样?
错误,返回MAP_FAILED
(3)如果文件偏移量为1000会怎样?
偏移量必须是4K的整数倍,否则会返回MAP_FAILED
(4)mmap什么情况下会调用失败?
-第二个参数:length=0;
-第三个参数:prot
-只指定了写权限
-prot PROT_READ | PROT_WRITE
第五个参数fd 通过open函数指定的O_RDONLY或者O_WRONLY。
(5)可以open的时候O_CREAT一个新文件来创建映射区嘛?
可以的,但是创建的文件的大小如果为0的话,肯定不行
可以对新的文件进行扩展
-lseek()
-truncate()
(6)mmap后关闭文件描述符,对mmap映射有没有影响?
int fd=open("XXX");
mmap(,,,,fd,,);
close(fd);
映射区还存在,创建映射区的fd被关闭,没有任何影响
(7)对ptr越界操作会怎么?
void *ptr=mmap(NULL,100,,,);
越界操作的是非法的内存->段错误。
记住吧!!