一、概念理解
存储映射I/O(Memory-mapped I/O)使一个磁盘文件与存储空间中的一个缓冲区相映射。于是当从缓冲区中取数据,就相当于读文件中的相应字节。与此类似,将数据存入缓冲区,则相应的字节就自动写入文件。这样,就可以在不使用read和write函数的情况下,使用地址(指针)完成I/O操作。
(本来在磁盘上的内容,想要去读写就需要open打开再去read或者write,但是一旦映射到了内存上,就可以利用地址使用指针去操作,这样对文件的操作就有了更多的方法,当然也就可以修改内存直接改变磁盘文件)
使用这种方法,首先应通知内核,将一个指定文件映射到存储区域中,这个映射工作可以通过mmap函数来实现
二、mmap函数原型
三、mmap建立映射区
#include
#include
#include
#include
#include
#include
#include
#include
void sys_err(const char *str)
{
perror(str);
exit(1);
}
//根据存储映射函数的参数依次地去进行操作
//mmap(映射区首地址NULL,映射区长度,读写属性,映射区属性是否同步shared/private,文件描述符,偏移即映射文件的区域)
int main(int argc, int char* argv[])
{
//假设字符串映射
char *p = NULL;
int fd;
fd = open("testmap", O_RDWR|O_CREATE|O_TRUNC,0644);
if(fd == -1)
{
sys_err("open error");
}
//但是大小为0的文件是不能映射的,因此要扩展文件大小
lseek(fd,10,SEEK_END);
write(fd,"\0",1);//拓展文件成11
int len = lseek(fd,0,SEEK_END);//用lseek获取文件大小
//或者用truncate/ftruncate获取文件大小
p = mmap(NULL,len,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);
if(p == MAP_FILED)
{
sys_err("mmap error");
}
//使用p对文件进行读写操作
strcpy(p,"hell0 mmap\n");//写操作
printf("-------%s",p);
int ret = munmap(p, lem);//释放映射区
if(ret == -1)
{
sys_ret("munmap error");
}
return 0;
}
mmap函数是创建共享映射,对应还有一个munmap函数,就是释放映射区
mmap函数的保险调用方式:
1,fd = open(“文件名”,O_RDWR);
2,mmap(NULL,有效文件大小,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);
父子等有血缘关系的进程之间用mmap建立的映射区来完成数据通信时,要再创建映射区时指定对应的标志位参数flags:
MAP_PRIVATE:私有映射,父子进程各自独占映射区
MAP_SHARED:共享映射,父子进程共享映射区
例子父进程创建映射区,然后fork子进程,子进程修改映射区内容,然后父进程读取映射区内容,查验是否共享
#include
#include
#include
#include
#include
#include
#include
#include
#include
int var = 100;//全局变量
void sys_err(const char *str)
{
perror(str);
exit(1);
}
int main(int argc, char *argv[])
{
//先创建mmap映射,需要打开一个文件
int *p;//指针类型需要不同场合不同指定
pid_t pid;
int fd;
fd = open("testmmap",O_RDWR|O_CREATE|O_TRUNC,0644);
if(fd<0)
{
perror("open error");
exit(1);
}
unlink("testmmap");//删除临时文件目录项,使之具备被删除条件
ftruncate(fd,4);//扩展文件
p = (int *)mmap(NULL,4,PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
if(p == MAP_FAILED)
{
perror("map error");
exit(1);
}
close(fd);//映射区建立完毕,即可关闭文件
//开始创建子进程
pid = fork();
if(pid == 0)//子进程
{
*p =2000;//写共享内存
var = 1000;
printf("child, *p = %d, var = %d\n", *p, var); //读共享内存
}else
{
//父进程
sleep(1);
printf("parent, *p = %d,var = %d", *p, var);
wait(NULL);
int ret = munmap(p,4);
if(ret == -1)
{
perror("munmap error");
exit(1);
}
}
return 0;
}
一个写进程
//写的一个进程
#include
#include
#include
#include
#include
#include
struct student
{
int id;
char name[256];
int age;
};
void sys_err(const char *str)
{
perror(str);
exit(1);
}
int main(int argc, char *argv[])
{
struct student stu = {10,"xiaoming",18};
struct student *p;
int fd;
open("testmap",O_REWR|O_CREATE|O_TRUNC,0664);
if(fd == -1)
{
sys_err("open error");
}
ftruncate(fd, sizeof(stu));
p = mmap(NULL,sizeof(stu),PROT_READ|PRROT_WRITE,MAP_SHARED,fd,0);
if(p == MAP_FAILED)
sys_err("mmap error");
close(fd);//映射好了就可以关闭文件
while(1)
{
memcpy(p, &stu, sizeof(stu));
stu.id++;
sleep(1);
}
munmap(p, sizeof(stu));
}
同理再一个读进程,只要两个进程都映射到一个内存中就可以进行通信,即两个进程对同一个文件创建映射区
注意:mmap与fifo的区别:
mmap:数据可以重复读取;fifo数据只能一次读取
==过了一下没有认真看xX
不需要关于文件的代码了
??可是它不需要文件的话怎么知道映射到哪里去?
嗷嗷嗷嗷嗷我们的目的是让两个进程进行通信,目的不是去改文件,ok没毛病了