mmap函数

写在前面:

内存共享的几种方式:

管道:简单、数据量较小

共享内存:最快

mmap:最高效

socket:最稳定

这篇文章重点分析一下mmap:

void *mmap(void *addr, size_t length, int prot, int flags,   

                      int fd, off_t offset);
int munmap(void *addr, size_t length);


如果addr参数为NULL,内核会自己在进程地址空间中选择合适的地址建立映射。如果addr不是NULL,则给内核一个提示,应该从什么地址开始映射,内核会选择addr之上的某个合适的地址开始映射。建立映射后,真正的映射首地址通过返回值可以得到。len参数是需要映射的那一部分文件的长度。offset参数是从文件的什么位置开始映射,必须是页大小的整数倍(在32位体系统结构上通常是4K)。fd是指文件描述符。

prot参数有四种取值:

  1. PROT_EXEC表示映射的这一段可执行,例如映射共享库
  2. PROT_READ表示映射的这一段可读
  3. PROT_WRITE表示映射的这一段可写
  4. PROT_NONE表示映射的这一段不可访问
flag参数有很多种取值,这里只讲两种,其它取值可查看mmap(2)
  • MAP_SHARED多个进程对同一个文件的映射是共享的,一个进程对映射的内存做了修改,另一个进程也会看到这种变化。
  • MAP_PRIVATE多个进程对同一个文件的映射不是共享的,一个进程对映射的内存做了修改,另一个进程并不会看到这种变化,也不会真的写到文件中去。
如果mmap成功则返回映射首地址,如果出错则返回常数MAP_FAILED。当进程终止时,该进程的映射

内存会自动解除,也可以调用munmap解除映射。munmap成功返回0,出错返回-1。

简单的使用样例:

将hello.c文件的内容复制到haha.c

#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>

int main()
{
  int fdin, fdout;

  void* src = NULL;
  void* dst = NULL;

  struct stat statbuf;
  
      if((fdin = open("./hello.c", O_RDONLY)) < 0)
      {
        perror("open");
        return 1;
      }

      if((fdout = open("haha.c", O_RDWR | O_CREAT | O_TRUNC, 0666)) < 0)
      {
        perror("open");
        return 1;
      }
      if(fstat(fdin, &statbuf) < 0)
      {
        perror("fstat");
        return 1;
      }
      //设置输出文件
      if(lseek(fdout, statbuf.st_size - 1, SEEK_SET)  == -1 )
      {
        perror("lseek");
        return 1;
      }
      if(write(fdout,"", 1) != 1)
      {
        perror("write");
        return 1;
      }
      if((src = mmap(NULL, statbuf.st_size, PROT_READ, MAP_SHARED,
         fdin, 0)) == MAP_FAILED)
      {
        perror("mmap fdin");
        return 1;
      }
      if((dst = mmap(NULL, statbuf.st_size, PROT_READ|PROT_WRITE,
          MAP_SHARED, fdout, 0)) == MAP_FAILED)
      {
        perror("mmap fdout");
        return 1;
      }
      memcpy(dst, src, statbuf.st_size);


  return 0;
}

mmap函数的优点:

1、对文件的读取操作跨过了页缓存,减少了数据的拷贝次数,用内存读写取代I/O读写,提高了文件读取效率。

2、实现了用户空间和内核空间的高效交互方式。两空间的各自修改操作可以直接反映在映射的区域内,从而被对方空间及时捕捉。

3、提供进程间共享内存及相互通信的方式。不管是父子进程还是无亲缘关系的进程,都可以将自身用户空间映射到同一个文件或匿名映射到同一片区域。从而通过各自对映射区域的改动,达到进程间通信和进程间共享的目的

4、可用于实现高效的大规模数据传输。内存空间不足,是制约大数据操作的一个方面,解决方案往往是借助硬盘空间协助操作,补充内存的不足。但是进一步会造成大量的文件I/O操作,极大影响效率。这个问题可以通过mmap映射很好的解决。 换句话说,但凡是需要用磁盘空间代替内存的时候, mmap 都可以发挥其功效。

猜你喜欢

转载自blog.csdn.net/bian_cheng_ru_men/article/details/80359938