一个磁盘文件与存储空间中的一个缓冲区相映射,于是当从缓冲区中取数据,就相当于读文件中的相应字节。于此类似,将数据存入缓冲区,则相应的字节就自动写入文件。这样,就可在不适用read和write函数的情况下,使用地址(指针)完成I/O操作。
void *mmap(void *addr, size_t length, int prot, int flags,int fd, off_t offset):创建映射区
addr :建立映射区的首地址,由Linux内核指定。使用时,直接传递NULL
length :欲创建映射区的大小(不能为0,不能给新创建的文件创建映射区,需要拓展新文件,
可以小于文件大小,可以大于文件的大小(但是毫无意义))
prot :映射区权限PROT_READ、PROT_WRITE、PROT_READ|PROT_WRITE、PROT_NONE、PROT_EXEC
flags :
MAP_SHARED:会将映射区所做的操作反映到物理设备(磁盘)上
MAP_PRIVATE:映射区所做的修改不会反映到物理设备
fd :用来建立映射区的文件描述符
offset :映射文件的偏移(4k的整数倍):MMU帮助完成映射,MMU单位是4K
int munmap(void *addr, size_t length):回收映射区
addr :mmap的返回值,映射空间的首地址
length :映射区的大小
例子:给文件创建映射区,再往映射区中写内容,看是否写入磁盘空间
#include
#include
#include
#include
#include
#include
#include
#include
int main(void)
{
int fd;
char*p;
fd = open("./my.txt",O_RDWR|O_CREAT,0664);
ftruncate(fd,sizeof("julian\n"));
p = mmap(NULL,sizeof("julian\n"),PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);
memcpy(p,"julian\n",sizeof("julian\n"));
munmap(p,sizeof("julian\n"));
close(fd);
return 0;
}
结果:在当前目录下创建一个my.txt文件,里面有写入映射区的内容
例子:父进程创建映射区,fork子进程,子进程修改映射区的内容,然后,父进程再读映射区,查看是否共享
#include
#include
#include
#include
#include
#include
#include
#include
int main(void)
{
int fd;
int*p;
pid_t pid;
int global_val=10;
fd = open("./my2.txt",O_RDWR|O_CREAT,0664); //临时文件,只为了创建映射区
ftruncate(fd,4);
unlink("./my2.txt"); //删除文件的目录项,使其进程介绍之后就被释放,删除
p = mmap(NULL,4,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);
close(fd);
pid=fork();
if(pid==0)
{
*p=10000;
global_val=9999;
printf("son ---*p:%d,global_val:%d\n",*p,global_val);
}
else
{
sleep(1);
printf("father---*p:%d,global_val:%d\n",*p,global_val);
wait(NULL);
munmap(p,4);
}
return 0;
}
结果:son 改了映射区*p的值,father读出来是修改过后的,但是global_val是各自进程独享的(0-3G用户空间),即使子进程改变了,父进程依然没改变
共享的条件是:mmap函数的Flags参数是shared,如果是private则结果如下:
#include
#include
#include
#include
#include
#include
#include
#include
int main(void)
{
int fd;
int*p;
pid_t pid;
int global_val=10;
fd = open("/dev/zero",O_RDWR);
p = mmap(NULL,4,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);// 4 根据自己定义映射区大小
close(fd);
pid=fork();
if(pid==0)
{
*p=10000;
global_val=9999;
printf("son ---*p:%d,global_val:%d\n",*p,global_val);
}
else
{
sleep(1);
printf("father---*p:%d,global_val:%d\n",*p,global_val);
wait(NULL);
munmap(p,4);
}
return 0;
}
例子:mmap_r.c:利用一个文件创建映射区,然后不断从中读数据(来自另一个进程写的结果)
#include
#include
#include
#include
#include
#include
#include
#include
struct student
{
int id;
char name[20];
};
int main(int argc,char* argv[])
{
int fd;
struct student student1;
struct student* p;
fd = open(argv[1],O_RDWR); //文件作为参数传进来
p = mmap(NULL,sizeof(student1),PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);
close(fd);
while(1)
{
printf("id=%d name=%s\n",p->id,p->name);
sleep(2);
}
munmap(p,sizeof(student1));
return 0;
};
#include
#include
#include
#include
#include
#include
#include
#include
struct student
{
int id;
char name[20];
};
int main(int argc,char* argv[])
{
int fd;
struct student student1={1,"julian"};
struct student* p;
fd=open(argv[1],O_RDWR|O_CREAT,0644);
p = mmap(NULL,sizeof(student1),PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);//
close(fd);
while(1)
{
sleep(1);
memcpy(p,&student1,sizeof(student1));
student1.id++;
}
munmap(p,sizeof(student1));
return 0;
}