mmap函数
#include <sys/mman.h>
void *mmap(void *addr, size_t length, int prot, int flags,int fd, off_t offset);
参数:
- void *addr建立映射区的首地址,由Linux内核指定,所以我们直接传递NULL。也就是说虽然这是一个参宿但是并不需要我们传递,当建立好映射区以后映射区的首地址将以返回值返回。
- size_t length建立映射区的大小,一般由创建映射区的文件的大小
- int prot用来表示映射区的权限(读,写,读写,执行,对于执行一般是操作系统调用)。- PROT_READ- PORT_WRITE- PROT_READ | PROT_WRITE
- int flags标志位参数,可以通过设置标志位来决定对映射区的修改是否反应到磁盘上。- MAP_SHEARD会将映射区所做的修改反映到物理设备上
- MAP_PRIVATE映射区所做的修改不会反映到物理设备
 
- int fd用来建立映射区的文件描述符
- off_t offset映射文件的偏移,用于截取文件的一部分建立映射区(4K的整数倍)
 返回值:
 成功返回创建映射区的首地址。失败返回- MAP_FAILED
ftruncate用来扩展文件大小
 关闭映射区:
int munmap(void *addr, size_t length);
第一个参数必须是映射区的首地址,长度可以变化
 成功返回0,失败返回-1
例如:
#include<stdio.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<unistd.h>
#include<fcntl.h>
#include<sys/mman.h>
#include<string.h>int main()
{int fd = open("mmap1file",O_CREAT | O_RDWR | O_TRUNC ,0644);if(-1 == fd){perror("open error");exit(1);}if(-1 == ftruncate(fd, 128)) 	{perror("ftruncate error:");exit(1);}char *p = mmap(NULL, lseek(fd,0,SEEK_END), PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);if(MAP_FAILED == p){perror("mmap error:");exit(1);}strcpy(p,"Hello mmap!");close(fd);	//关闭文件if(-1 == munmap(p,128)){perror("munmap error:");exit(1);}return 0;
}注意事项
- 可以用malloc创建大小为0 的堆空间,并且可以free, 不可以创建大小为0 的映射区
- 如果文件是以只读方式打开的就不能改变文件大小
- 如果文件是以只读方式打开,那么不能将映射区设置为MAP_SHARED,但是可以将映射区设置为MAP_PRIVATE
- 如果文件以只写方式打开,将无法建立映射区,错误信息为Permission denied,因为创建映射区的过程中其实有一次隐含的读操作
- 创建映射区的权限要小于等与文件的权限
- 偏移量必须是页(4K)的整数倍
- 因为mmap容易出错,所以一定要保留mmap的返回值,并通过perror输出错误信息
- 关闭映射区的时候munmap的第一个参数必须是映射区的首地址
- 建立映射区以后文件即使关闭也不影响,如果是MAP_SHARED的话仍旧会修改磁盘文件
利用共享内存在父子进程之间通信
用于通信的时候我们创建一个临时文件,成功创建映射区以后将文件关闭不再使用。
具体的方法是:
- 创建一个文件
- 使用ftruncate函数改变文件大小
- 使用unlink函数删除目录项(创建临时文件)
- 建立映射区
- 关闭文件
在父子进程间通信时MAP_SHARED指的是共享同一个映射区,MAP_PRIVATE指的是不共享映射区,父子进程分别占用
匿名映射
因为正常mmap函数必须依赖一个文件,虽然这个文件没有存在的必要,因此我们需要open、ftruncate、unlink、close比较麻烦。因此我们可以使用匿名映射较为方便地创建映射区。
int *p = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
len可以根据我们的需要修改大小。
 MAP_ANONYMOUS表示匿名通信,可以简写为MAP_ANON
需要注意的是MAP_ANONYMOUS只能够在Linux系统中使用,在其他类Unix系统中不可以使用,在其他系统中使用字符设备文件/dev/zero
int fd = open("/dev/zero", O_RDWR);
p = (int*)mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
mmap无血缘关系进程通信
同一个文件创建的是一个映射区,因此如果我们想要在没有血缘关系,就需要通过同一个文件来建立映射区
strace 可执行文件追踪程序里面所使用的系统调用有哪些
其实Linux系统对文件的操作是通过mmap进行的