美文网首页
Linux 进程间通信 -- 文件mmap映射

Linux 进程间通信 -- 文件mmap映射

作者: brownfeng | 来源:发表于2020-02-03 22:24 被阅读0次

    Linux 进程间通信 -- 文件mmap映射

    打开一个文件, 并且指定文件中的一个区域, 映射到内存中, 然后直接操作那个内存, 就能实现进程间通信!!!因为是内存操作, 所以速度是最快的.

    使用mmap进程通信速度是最快的.

    函数mmap:打开一个文件,指定一个文件的区域,作为一个区域,映射到内存中,以后就直接操作那个内存,就能够实现进程间的通信。因为是内存操作,所以速度最快。

    #include <sys/mman.h>
    void *mmap(void *addr, size_t length, int prot, int flags,int fd, off_t offset);
    int munmap(void *addr, size_t length);
    

    参数解释:

    • fd: 需要映射文件的文件描述符

    • addr:固定NULL

    • length:拿出文件中的多长的一段,映射到内存。

    • prot - PROT_READ 和 PROT_WRITE 用的多

      • PROT_EXEC Pages may be executed
      • PROT_READ Pages may be read.
      • PROT_WRITE Pages may be written.
      • PROT_NONE Pages may not be accessed
    • flags - 是否可以共享!!!

      • MAP_SHARED:对内存里的值进行修改,会反映到文件,也就是文件也被修改。
      • MAP_PRIVATE:对内存里的值进行修改,不会反映到文件,文件不会被修改。
    • offset:从文件内容中的哪个位置开始拿。

    • 返回值

      • 成功:可用的内存的首地址
      • 失败:MAP_FAILED (that is, (void *) -1)

    释放内存映射区。

    #include <sys/mman.h>
    int munmap(void *addr, size_t length);
    
    • addr:mmap的返回值
    • length:mmap创建的长度
    • 返回值:成功0;失败-1.

    简单dmeo, 需要注意mem.txt文件需要内容长度最少大于8byte

    #include <fcntl.h>
    #include <stdio.h>
    #include <string.h>
    #include <sys/mman.h>
    #include <sys/stat.h>
    #include <sys/types.h>
    #include <unistd.h>
    
    int main() {
      // mem.txt filesize should > 8!!
      int fd = open("mem.txt", O_RDWR);
      // create mmap
      char *mem = (char *)mmap(NULL, 8, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
      if (mem == MAP_FAILED) {
        perror("mmap err");
        return -1;
      }
    
      printf("%s\n", mem);
      strcpy(mem, "hello");
    
      // release mmap
      munmap(mem, 8);
      close(fd);
    }
    

    使用mmap有多个需要注意的问题:

    1. 创建mmap的地址和释放地址必须一致.
    2. 在映射区越界操作情况如下(一定要尽量避免!!!):
      1. open文件size > 要写入的size > mmap参数的length:能够全部写入文件。
      2. open文件size < 要写入的size > mmap参数的length:不能全部写入文件,能够写入的size是open文件的size
    3. 偏移量offset必须是4K的整数倍(0, 4 * 1024, ...), 可以用stat看到mmap的IO Block是4096
    4. 如果文件描述符先关闭, 对 mmap 映射没有影响
    5. open的时候,可以用新创建一个文件的方式,来创建映射区吗? 会导致Bus error(core dumped), 创建的文件的size为0,所以出上面的错误。新创建一个文件后,马上把文件大小扩展一下就不会发生错误了。int fd = open("mem", O_RDWR|O_CREAT, 0666);
      ftruncate(fd, 8);//把新创建的文件mem的大小扩展为8.
    6. open文件时,选择O_WRONLY时候, mmap函数出错,错误Permission denied, 因为要把文件的内容读到内存,所以隐含一次读取操作,所以没有读的权限的话,就出这个错误。
    7. 当选择MAP_SHARED的时候,open文件选择O_RDONLY, prot不能是PROT_READ|PROT_WRITE, 会导致 mmap 函数出错,错误Permission denied, MAP_SHARED的时候会去写文件,但是open的时候只有读权限,所以权限不够。

    用mmap实现父子进程间通信的例子:

    参数flags必须是MAP_SHARED,因为2个进程间通信,需要互相读写,所以必须是MAP_SHARED, 并且我们使用open + ftruncate的组合, 重新创建一个文件.

    #include <fcntl.h>
    #include <stdio.h>
    #include <sys/mman.h>
    #include <sys/stat.h>
    #include <sys/types.h>
    #include <sys/wait.h>
    #include <unistd.h>
    
    int main() {
      int fd = open("mem.txt", O_RDWR | O_CREAT);
      ftruncate(fd, 4);
      int *mem = (int *)mmap(NULL, 4, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
      if (mem == MAP_FAILED) {
        perror("mmap");
        return -1;
      }
      pid_t pid = fork();
    
      if (pid == 0) {
        *mem = 100;
        printf("child:mem=%d\n", *mem);
        sleep(3);
        printf("child:mem=%d\n", *mem);
      } else if (pid > 0) {
        sleep(1);
        printf("parent:mem=%d\n", *mem);
        *mem = 200;
        printf("parent:mem=%d\n", *mem);
        wait(NULL);
      }
    
      munmap(mem, 4);
      close(fd);
    }
    

    从这个实例看到, 必须要先打开文件, 再使用mmap创建内存映射区(同时使用MAP_SHARRED), 比较麻烦, Linux也提供另外一种内存映射 -- 匿名映射

    相关文章

      网友评论

          本文标题:Linux 进程间通信 -- 文件mmap映射

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