美文网首页
MMAP-存储映射I/O

MMAP-存储映射I/O

作者: 烫烫烫烫烫烫烫烫烫烫烫烫 | 来源:发表于2019-05-19 09:13 被阅读0次

    存储映射I/O 介绍

        存储映射IO(Memory-mapped I/O) 使用一个磁盘文件与存储空间的一个缓冲区相映射。于是当缓冲区中取出数据,就相当于读文件中的相应字节。于此类似。间数据存入缓冲区,则相应的字节就会自动写入文件。因为数据已经写入文件,即使机器重启数据还在。


    TIM截图20190517162610.png

    mmap函数

        使用这种方法,首先应通知内核,间一个指定文件映射到存储区域中。可以通过mmap函数来实现。

    函数原型 :
        void *mmap(void *adrr, size_t length, int prot, int flags, int fd, off_t offset); 
    参数:
        addr:建立映射区的首地址,有Linux内核指定。使用时传NULL即可
        length:与创建映射取的大小
        prot: 映射区权限PROT_READ、PROT_WRITE、PROT_READ|PROT_WRITE
        flags:标志位参数(常用于设定更新物理区域、设置共享、创建匿名映射区)
                MAP_SHARED:  会将映射区所做的操作反映到物理设备(磁盘)上。
                MAP_PRIVATE: 映射区所做的修改不会反映到物理设备。
       fd: 用来建立映射区的文件描述符
       offset: 映射文件的偏移(4k的整数倍)
    
    

    munmap函数

    当不需要这个映射内存时通过munmap函数来释放

    函数原型:
        int munmap(void *addr, size_t length);
    参数:
        addr :mmap的返回值
        length:释放区域的长度
    
    

    示例代码

    mem.txt文件

    jjjjjjjj
    

    mmap.c文件

    #include <stdio.h>
    #include <unistd.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    #include <sys/mman.h>
    #include <string.h>
    
    int main()
    {
    #include <stdio.h>
    #include <unistd.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    #include <sys/mman.h>
    #include <string.h>
    
    int main()
    {
        int fd = open("mem.txt",O_RDWR);//创建并且截断文件
        //int fd = open("mem.txt",O_RDWR|O_CREAT|O_TRUNC,0664);//创建并且截断文件
    
    
        //创建映射区
       char *mem = mmap(NULL,20,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);
        //char *mem = mmap(NULL,8,PROT_READ|PROT_WRITE,MAP_PRIVATE,fd,0);
    
        if(mem == MAP_FAILED){
            perror("mmap err");
            return -1;
        }
      
        //拷贝数据
        strcpy(mem,"helloworld");
    //    mem++;
        //释放mmap
        if(munmap(mem,20) < 0){
            perror("munmap err");
        }
        close(fd);
        return 0;
    }
    
    

    运行代码之后,发现mem.txt文件内容已经改变

    [root@VM_0_11_centos linux]# cat mem.txt
    helloworl[root@VM_0_11_centos linux]#

    **读写例 **

    #include <stdio.h>
    #include <unistd.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <sys/mman.h>
    #include <fcntl.h>
    #include <sys/wait.h>
    
    typedef struct _Student{
        int sid;
        char sname[20];
    }Student;
    
    int main(int argc,char *argv[])
    {
        //open file 
        int fd = open(argv[1],O_RDWR);
        //mmap 
        int length = sizeof(Student);
        Student *stu = mmap(NULL,length,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);
        if(stu == MAP_FAILED){
            perror("mmap err");
            return -1;
        }
        //read data 
        while(1){
            printf("sid=%d,sname=%s\n",stu->sid,stu->sname);
            sleep(1);
        }
        //close and munmap 
        munmap(stu,length);
        close(fd);
        return 0;
    }
    

    写示例

    #include <stdio.h>
    #include <unistd.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <sys/mman.h>
    #include <fcntl.h>
    #include <sys/wait.h>
    
    typedef struct  _Student{
        int sid;
        char sname[20];
    }Student;
    
    int main(int argc,char *argv[])
    {
        if(argc != 2){
            printf("./a.out filename\n");
            return -1;
        }
        
        // 1. open file 
        int fd = open(argv[1],O_RDWR|O_CREAT|O_TRUNC,0666);
        int length = sizeof(Student);
    
        ftruncate(fd,length);
    
        // 2. mmap
        Student * stu = mmap(NULL,length,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);
        
        if(stu == MAP_FAILED){
            perror("mmap err");
            return -1;
        }
        int num = 1;
        // 3. 修改内存数据
        while(1){
            stu->sid = num;
            sprintf(stu->sname,"xiaoming-%03d",num++);
            sleep(1);//相当于没隔1s修改一次映射区的内容
        }
        // 4. 释放映射区和关闭文件描述符
        munmap(stu,length);
        close(fd);
    
        return 0;
    }
    
    

    map的一些问题

    1.如果对mem越界操作会怎样?

    多出的数据会丢失,尽量避免这样的操作

    2.如果文件描述符向关闭,对mmap映射有没有影响

    没有影响

    3.open的时候,可以新创建一个文件来创建映射区吗?

    不可以,使用的文件大小不能为0

    4.如果文件偏移随便填一个数会怎么样?

    运行时会报错

    匿名映射

         通过使用我们发现,使用映射区来完成文件读写十分方便,赋值进程通信也比较容易。但是缺陷是,每次创建映射区一定要依赖一个文件才能实现。通常为了建立映射区要open一个temp文件,创建好了再unlink,close掉,比较麻烦。可以直接使用匿名映射来代替。Linux系统给我们提供了创建匿名映射区的方法,无需依赖一个文件,即可创建映射取。同样需要借助标志位参数flags来指定。
    示例代码:

    #include <stdio.h>
    #include <unistd.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <sys/mman.h>
    #include <fcntl.h>
    #include <sys/wait.h>
    
    int main()
    {
        //修改创建的参数
        int *mem = mmap(NULL,4,PROT_READ|PROT_WRITE,MAP_SHARED|MAP_ANON,-1,0);
    
        if(mem == MAP_FAILED){
            perror("mmap err");
            return -1;
        }
        ...
    
    

    相关文章

      网友评论

          本文标题:MMAP-存储映射I/O

          本文链接:https://www.haomeiwen.com/subject/ytsfzqtx.html