• 存储映射--mmap


    存储映射

    • 使一个磁盘文件与存储空间中的一个缓冲区相映射。
    • 当从缓冲区中取数据,就相当于读文件中的相应字节。
    • 将数据存入缓冲区,则相应的字节就自动写入文件。

    使用这种方法,首先应通知内核,将一个指定文件映射到存储区域中。这个映射工作可以通过mmap函数来实现。不通过IO。直接操作内存,效率更高。

    mmap函数

    函数原型

    #include <sys/mman.h>
    
    void *mmap(void *addr, 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: 映射区所做的修改不会反映到物理设备。
      • MAP_ANON:匿名映射,不需要已存在的文件进行映射。fd传-1,只能用于亲缘进程间。
    • fd: 用来建立映射区的文件描述符。
    • offset: 起点的偏移量,必须是4K的整数倍。因为映射至少一页,比如5000字节的文件,映射内存也是2页大小,不会正好是5000.

    Note

    使用MAP_SHARED的时候,要注意打开文件的权限>=映射区权限。因为如果文件没有写权限,映射区有写权限,那么映射区是无法写入文件的,这和MAP_SHARED的目的相反。如是MAP_PRIVATE就没有此要求。

    另外,文件打开权限起码要是可读的,如果不可读,那么怎么读取数据映射到内存呢?

    返回值

    • 成功调用返回映射的地址。
    • 失败时返回MAP_FAILED,即void * (-1)。设置errno.

    munmap函数

    函数原型:

    #include <sys/mman.h>
    int munmap(void *addr, size_t length);
    

    此函数较为简单,释放映射区,首地址为addr,长度为length.

    • 成功的时候返回0.
    • 失败返回-1且置errno。

    应用实例

    实现进程间的通信,写进程将一份文件映射到内存,并且每秒写入(覆盖写入)不同的字符串,读进程一直去读。

    写进程:

    struct Person{         
          char name[30];     
          int num;           
      };
    int main(int argc, char const* argv[])
    {
        //打开文件,作为映射
        int fd = open("memTest2.txt", O_RDWR);
        //int fd = open("memTest2.txt", O_RDWR);
        int length = sizeof(struct Person);
        ftruncate(fd, length);
        printf("fd=%d
    ", fd);
        //映射
        struct Person* mem = (struct Person*)mmap(0, length, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
        if (mem == MAP_FAILED) {
            perror("mmap err");
            return -1;
        }
        printf("映射区地址:%0x
    ", mem);
        int num = 1;
        while (1) {
            mem->num = num++;
            sprintf(mem->name, "I am a Person%03d", mem->num);
            sleep(1);
        }
      
        //释放
        munmap(mem, length);
        close(fd);
        return 0;
        }
    

    读进程:

    struct Person{         
          char name[30];     
          int num;           
      };
      
      int main(int argc, char const* argv[]) 
      {
          //打开文件,作为映射
          int fd = open("memTest2.txt", O_RDWR);
          int length = sizeof(struct Person);
          printf("fd=%d
    ", fd);    
          //映射             
          struct Person* mem = (struct Person *)mmap(0, length, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
          if(mem == MAP_FAILED)
          {
              perror("mmap err");       
              return -1;     
          }
          printf("映射区地址:%0x
    ", mem);
          while (1) {        
              printf("name=%s,num=%d
    ", mem->name,mem->num);
              sleep(1);      
          }                  
      
          //释放
          munmap(mem, length);
          close(fd);         
          return 0;          
      }
  • 相关阅读:
    动态发布接口
    高频访问IP弹验证码架构图 让被误伤的用户能及时自行解封的策略
    C/C++ Lua通信
    Mercurial
    goroutine chan 通道
    HotSpot VM
    # 释放内存 filter_res_q_l = filter_res_q_l[-2048:] filter_res_a_l = filter_res_a_l[-2048:]
    mongo 统计数据磁盘消耗
    不基于语义的基于字符串交集的字符串相似度比较
    拥塞控制 流量控制
  • 原文地址:https://www.cnblogs.com/love-jelly-pig/p/10063442.html
Copyright © 2020-2023  润新知