linux--多进程开发(6)IPC之内存映射
内存映射
是指将磁盘中的数据映射到内存的虚拟地址空间之中,在内存中进行操作的内容会同步到磁盘中的文件中。
创建内存映射
void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);
【功能】:将一个文件或者设备的数据映射到内存中
【参数】:
addr:设置为 NULL时, 由内核指定映射的地址(推荐做法)
length : 要映射的数据的长度,【这个值不能为0。建议使用文件的长度】,获取文件的长度:stat,lseek
prot : 对申请的内存映射区的操作权限,【这个权限要在用open打开的权限之内】
PROT_EXEC :可执行的权限
PROT_READ :读权限
PROT_WRITE :写权限
PROT_NONE :没有权限
flags:
MAP_SHARED : 映射区的数据会自动和磁盘文件进行同步,进程间通信,必须要设置这个选项
MAP_PRIVATE` :不同步,内存映射区的数据改变了,对原来的文件不会修改,会重新创建一个新的文件。(写时复制机制)
fd: 需要映射的那个文件的文件描述符,通过open得到,open的是一个磁盘文件
offset:偏移量,一般进行特殊指定(指定为0即可),如果使用必须指定的是 `4k` 的整数倍,0表示不偏移
【返回值】:返回【创建的内存的首地址】。失败返回`MAP_FAILED(即把-1转为地址了(void *) -1)
int munmap(void *addr, size_t length);
【功能】:释放内存映射
【参数】:
addr : 要释放的内存的首地址
length : 要释放的内存的大小,要和`mmap`函数中的length参数的值一样
内存映射在进程间通信的种类:
有关系的进程(亲缘关系)
- 准备一个大小不是0的磁盘文件
- 还没有子进程的时候,先创建内存映射区
- 有了内存映射区之后,创建子进程
- 父子进程共享创建的内存映射区
没有关系的进程
- 准备一个大小不是0的磁盘文件
- 进程1和进程2 分别 通过磁盘文件创建内存映射区,得到一个操作这块内存的指针
注意事项
- mmap创建内存映射区的时候,注意prot的权限一定要包含读的权限,并且权限一定要小于open的权限,不能和open的权限有冲突。即PROT_READ或者PROT_READ|PROT_WRITE。
- 一个文件对应一个内存映射区,因此也可以进行文件的复制,因为映射返回的是数据在内存的首地址,而更改这些数据又可以使得磁盘的数据发生改变,所以可以实现一个文件复制到另一个文件的操作。
- 如果对mmap返回的ptr做ptr++操作会出现什么状况? 是可以操作的,但回收资源的时候,ptr不是原来的ptr了,munmap会失败。
- 什么情况下mmap会调用失败?
1)第二个参数len=0
2)第三个参数的prot权限不包含读权限以及超过了open的权限
3)偏移量不为4k的整数倍,返回MAP_FAILED - open的时候可以O_CREAT创建一个新文件来创建映射区吗? 可以,但记得要扩展文件,否则文件的大小为0,用lseek或者truncate
- mmap映射之后,关闭fd有影响吗? 映射区还在,关闭fd没有任何影响,因为已经形成了一个映射
- 对ptr越界操作会? 操作的是非法内存,会出现段错误
int len = lseek(fdSource, 0, SEEK_END); //获取文件大小
truncate("target.txt", len); //扩展文件长度