1.mmap函数
所需头文件:#include<sys/mman.h>
函数原型:void* mmap(void* addr, size_t length, int prot, int flags, int fd, off_t offset)
参数:
第一个参数void* addr
是映射区的首地址,传NULL
,让内核去指定,返回值用来指定映射区的首地址。
第二个参数是映射区的大小size_t length
,由于32bit的linux内核虚拟地址空间是由4KB大小的页面组织的,实际大小是4KB的整数倍。不能指定为0,否则调用失败!一般来讲,文件多大,length就指定多大。
第三个参数是映射区的权限int prot
, PROT_READ (映射区必须要有读权限)、 PROT_WRITE。
第四个参数 int flags
指示标志位参数, MAP_SHARED 数据会同步到磁盘、MAP_PRIVATE 数据不会同步到磁盘。
第五个参数是文件描述符fd
,要映射的文件对应的文件描述符fd。使用open系统调用获取文件描述符。
第六个参数off_t offset
映射文件指针的偏移量,偏移量必须是4KB的整数倍,一般传入0即可,除非有特殊的需求。
返回值:
成功时,返回内存映射区的首地址。
失败,MAP_FAILED (void)-1*。
功能: 将磁盘文件的数据映射到内存,用户通过修改内存就能修改磁盘文件。
(1)使用普通文件提供的内存映射:
适用于任何进程之间。此时,需要打开或创建一个文件,然后再调用mmap()
典型调用代码如下:
int fd = open(name, flag, mode);
if(fd<0) ...
void* ptr = mmap(NULL, len , PROT_READ|PROT_WRITE, MAP_SHARED , fd , 0);
通过mmap()实现共享内存的通信方式有许多特点和要注意的地方,可以参看UNIX网络编程第二卷。
(2)适用于具有亲缘关系的进程之间。由于父子进程特殊的亲缘关系,在父进程中先调用mmap(),然后调用 fork()。那么在调用fork()之后,子进程继承父进程匿名映射后的地址空间,同样也继承mmap()返回的地址,这样,父子进程就可以通过映射区 域进行通信了。注意,这里不是一般的继承关系。一般来说,子进程单独维护从父进程继承下来的一些变量。而mmap()返回的地址,却由父子进程共同维护。 对于具有亲缘关系的进程实现共享内存最好的方式应该是采用匿名内存映射的方式。此时,不必指定具体的文件,只要设置相应的标志即可。
2.munmap函数
所需头文件:#include<sys/mman.h>
函数原型: int munmap(void* addr,size_t length)
参数:
第一个参数void* addr
,mmap的返回值,是映射区的首地址。
第二个参数,映射区的长度。
返回值:
示例代码
//mmap.c
#include<sys/mman.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
int main(){
//打开一个文件
int fd = open("a.txt",O_RDWR);
int len = lseek(fd,0,SEEK_END);
//创建内存映射区
void* p = mmap(NULL,len,PORT_READ | PORT_WRITE,MAP_SHARED,fd,0);
if(p == MAP_FAILED){
perrot("mmap error");
exit(1);
}
printf("%s\n",(char*)p);
//释放内存映射区
munmap(p,len);
close(fd);
return 0;
}
a.txt
gcc -o mmap mmap.c