美文网首页
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