存储映射I/O(Memory-mapped I/O)使一个磁盘文件与存储空间中的一个缓冲区相映射
于是当从缓冲区取数据,就相当于读文件中的相应字节。于此类似,将数据刷入缓冲区,则相应的字节就自动写入文件,这样,就可在不适用read和write函数的情况下,使用地址完成I/O操作
共享内存可以说是最有用的进程间通信方式,也是最快的IPC形式,因为进程可以直接读写内存,而不需要任何数据拷贝
mmap 函数
#include<sys/mman.h>
void *mmap(void *addr,size_t length,int prot,int flags,int fd,off_t offset);
/*
功能 一个文件或者其它对象映射进内存
参数 addr 指定映射的超始地址,通常为NULL,由系统指定
length 映射到内存的文件长度
prot 映射区的保护方式 读 PROT_READ 写 PROT_WRITE 读写 PROT_READ|PROT_WRITE
flags 映射区的特性 MAP_SHARED 写入映射区的数据会复制回文件 且允许其它映射该文件的进程共享
MAP_PRIVATE 对映射区的写入操作会产生一个映射区的复制(copy-on-write),对此区域所做的修改不会写回原文件
fd 由open 返回的文件描述符,代表要映射的文件
offset 以文件开始处的偏移量,必须是4K整数倍,通常为0,表示从文件头开始映射
返回值 成功 返回创建的映射区首地址 失败 MAP_FAILED 宏
*/
munmap 函数
#include<sys/man.h>
int munmap(void *addr,size_t length);
/*
功能 释放内存映射区
参数 addr 使用mmap函数创建的映射区首地址
length 映射区大小
返回值 成功 0 失败 -1
*/
代码
// mmap1.c
#include<stdlib.h>
#include<string.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<unistd.h>
#include<fcntl.h>
#include<sys/mman.h>
#include<stdio.h>
int main(){
int fd=-1;
int ret=-1;
void *addr=NULL;
//打开文件
fd=open("test",O_RDWR);
if(-1==fd){
perror("open");
return 1;
}
//映射到内存
addr=mmap(NULL,1024,PROT_READ | PROT_WRITE,MAP_SHARED,fd,0);
if(addr==MAP_FAILED){
perror("mmap");
return 1;
}
printf("mmap successn");
//关闭文件
close(fd);
//写文件
memcpy(addr,"abc123",6);
//断开映射
munmap(addr,1024);
return 0;
}
// 编译 gcc mmap1.c -o mmap1
// 创建 test echo "hello word">tet
// 运行 ./mmap1
// cat test 输出 abc12word
//
//
注意事项
创建映射区的过程中,隐含着一次对映射文件的读操作
当MAPSHARED 时,要求 映射区权限<=文件打开的权限,而 MAP_PRIVATE 则无所谓,因为mmap中权限是对内存的限制
映射区释放与文件关闭无关,只要映射创建成功,文件可以立即关闭
特别注意,当映射文件大小为0时,不能创建映射区,所以,用于映射的文件必须要有实际大小,mmap 常常会出现总线错误(Bus error),通常是由于共享文件存储空间大小引起的。
munmap传入的地址一定是mmap的返回地址,不能用指针++操作
文件偏移量必须为4K的整数倍
mmap 创建映射区出错概率非常高,一定要检查返回值,确保映射区建立成功再进行后续