void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);
功能:申请一块内存空间,可以将它作为进程通讯的共享内存,也可以将文件直接映射到其中。
返回值:成功返回指向内存的首地址,失败返回MAP_FAILED并设置errno
参数
- addr:允许用户将某个特定的地址设为这段内存的起始地址,设为NULL表示系统自动分配一个地址
- prot:访问权限PROT_READ、PROT_WRITE、PROT_EXEC、PROT_NONE
- fd:被映射的文件对应的文件描述符
- offset:设置从文件的何时开始映射
- flags:控制内存段内容被修改后程序的行为
flags | |
---|---|
MAP_SHARED | 在进程间共享这段内存。对内存的修改将反映到被映射的文件中 |
MAP_PRIVATE | 内存段为调用进程私有。对内存的修改不会反映到被映射的文件中 |
MAP_ANONYMOUS | 这段内存不是从文件映射而来的。其内容被初始化为全0。这种情况下,mmap函数的最后两个参数将被忽略 |
MAP_FIXED | 内存段必须位于addr参数指定的地址处。addr必须是内存页面大小(4096字节)的整数倍 |
MAP_HUGETLB | 按照"大内存页面"来分配内存空间,大内存页面的大小可以通过/proc/meminfo文件查看 |
int munmap(void *addr, size_t length);
返回值:成功返回0,失败返回-1并设置errno
1. 父子进程是否会共享mmap创建的内存映射区?
答:父子进程会共享mmap创建的内存映射区
2.1 使用mmap在[父子]进程间通信
- 父子进程如何使用mmap进行通信?
父子进程都使用父进程调用mmap返回的指向内存映射区的ptr指针 - mmap创建的内存映射区,是非阻塞的。
与pipe不同的是,内存映射区是非阻塞的—>因此应该控制父子进程的read和write顺序。(必须保证内存映射区中被写入数据时,才去读数据)
int main(){
int len=4096;
//创建匿名的内存映射区
//第四个参数,加上MAP_ANION:MAP_SHARED|MAP_ANON
//fd指定为-1
void* ptr=mmap(NULL,len,PROT_READ|PROT_WRITE,MAP_SHARED|MAP_ANON,-1,0);
if(ptr==MAP_FAILED){
perror("mmap");
exit(1);
}
pid_t pid=fork();
if(pid==-1){
perror("fork");
exit(1);
}
if(pid>0){ //parent
strcpy((char*)ptr,"I am a student"); //向mmap中写入数据
wait(NULL);
}
if(pid==0){//chile
printf("%s\n",(char*)ptr); //从mmap中读取数据
}
munmap(ptr,len);
return 0;
}
2.2 使用mmap在[无血缘关系]进程间通信**
Question:父子进程如何使用mmap进行通信?(即:父子进程通信,怎么找到同一个mmap内存映射区?)
答:本地磁盘上的(绑定相同的文件)
- 如何通信? 答:不能使用匿名映射的方式(只能借助磁盘文件创建映射区)
- 进程A(a.c) 进程B(b.c)通信案例
- a.c
int fd=open("hello");
void* ptr=mmap(.....fd.....);
对映射区ptr进行读写操作
- b.c
int fd=open("hello");
void* ptr=mmap(.....fd.....);
对映射区ptr进行读写操作