织梦CMS - 轻松建站从此开始!

罗索实验室

当前位置: 主页 > 基础技术 > Linux开发专题 >

Linux-mmap函数介绍

jackyhwei 发布于 2011-04-19 20:20 点击:次 
mmap系统调用并不是完全为了用于共享内存而设计的。它本身提供了不同于一般对普通文件的访问方式,进程可以像读写内存一样对普通文件的操作。而Posix或系统V的共享内存IPC则纯粹用于共享目的,当然mmap()实现共享内存也是其主要应用之一。
TAG:

mmap函数是unix/linux下的系统调用,来看《Unix Netword programming》卷二12.2节对mmap的介绍:
The mmap function maps either a file or a Posix shared memory object into the address space of a process.We use this function for three purposes:
1. with a regular file to provide memory-mapped I/O
2. with special files to provide anonymous memory mappings
3. with shm_open to provide Posix shared memory between unrelated processes

         mmap系统调用并不是完全为了用于共享内存而设计的。它本身提供了不同于一般对普通文件的访问方式,进程可以像读写内存一样对普通文件的操作。而Posix或系统V的共享内存IPC则纯粹用于共享目的,当然mmap()实现共享内存也是其主要应用之一。
         mmap系统调用使得进程之间通过映射同一个普通文件实现共享内存。普通文件被映射到进程地址空间后,进程可以像访问普通内存一样对文件进行访问,不必再调用read(),write()等操作。

         我们的程序中大量运用了mmap,用到的正是mmap的这种“像访问普通内存一样对文件进行访问”的功能。实践证明,当要对一个文件频繁的进行访问,并且指针来回移动时,调用mmap比用常规的方法快很多。
         来看看mmap的定义:
void *mmap(void *addr, size_t len, int prot, int flags, int fd, off_t offset);

         参数fd为即将映射到进程空间的文件描述字,一般由open()返回,同时,fd可以指定为-1,此时须指定flags参数中的MAP_ANON,表明进行的是匿名映射(不涉及具体的文件名,避免了文件的创建及打开,很显然只能用于具有亲缘关系的进程间通信)。

         len是映射到调用进程地址空间的字节数,它从被映射文件开头offset个字节开始算起。

         prot参数指定共享内存的访问权限。可取如下几个值的或:PROT_READ(可读),PROT_WRITE(可写),PROT_EXEC(可执行),PROT_NONE(不可访问)。

         flags由以下几个常值指定:MAP_SHARED, MAP_PRIVATE, MAP_FIXED。其中,MAP_SHARED,MAP_PRIVATE必选其一,而MAP_FIXED则不推荐使用。
         如果指定为MAP_SHARED,则对映射的内存所做的修改同样影响到文件。如果是MAP_PRIVATE,则对映射的内存所做的修改仅对该进程可见,对文件没有影响。

         offset参数一般设为0,表示从文件头开始映射。

         参数addr指定文件应被映射到进程空间的起始地址,一般被指定一个空指针,此时选择起始地址的任务留给内核来完成。函数的返回值为最后文件映射到进程空间的地址,进程可直接操作起始地址为该值的有效地址。

         看看下面这个图(来自《Unix Netword programming》卷二12.2节),对mmap进一步加深印象:

         这里不再详细介绍mmap的参数,读者可参考mmap手册页或者《Unix Netword programming》卷二12.2节获得进一步的信息。
         最后,举个例子来结束本节。4.2节说过,Fileinformation数组是以二进制的形式写进一个叫inforindex的文件中。那么,当要访问Fileinformation数组时,代码类似这样:
  1. struct stat st; 
  2. char buffer=” inforindex”; 
  3. Fileinformation *_fileinfoIndexptr = NULL; 
  4. if(stat(buffer,&st)<0) 
  5.        fprintf(stderr,"error to stat %s\n",buffer); 
  6.        exit(-1); 
  7. // mmap the inforindex to _fileinfoIndexptr 
  8. int fd=open(buffer, O_RDONLY); 
  9. if(fd<0) 
  10.        printf("error to open %s\n",buffer); 
  11.        exit(-1); 
  12. _fileinfoIndexptr   = (Fileinformation*)mmap(NULL,st.st_size
  13. , PROT_READ,MAP_SHARED,fd,0); 
  14.  
  15. if(MAP_FAILED == _fileinfoIndexptr) 
  16.        printf("error to mmap %s\n",buffer); 
  17. close(fd); 
  18.        exit(-1); 
  19. close(fd); 

示例代码: http://zhoulifa.bokee.com/6614538.html

下面这个例子显示了把文件映射到内存的方法

源代码是:

  1. /************关于本文档******************************************** 
  2. *filename: mmap.c 
  3. *purpose: 说明调用mmap把文件映射到内存的方法 
  4. *wrote by: zhoulifa(zhoulifa@163.com) 周立发(http://zhoulifa.bokee.com) 
  5. Linux爱好者 Linux知识传播者 SOHO族 开发者 最擅长C语言 
  6. *date time:2008-01-27 18:59 上海大雪天,据说是多年不遇 
  7. *Note: 任何人可以任意复制代码并运用这些文档,当然包括你的商业用途 
  8. * 但请遵循GPL 
  9. *Thanks to: 
  10. *                Ubuntu 本程序在Ubuntu 7.10系统上测试完全正常 
  11. *                Google.com 我通常通过google搜索发现许多有用的资料 
  12. *Hope:希望越来越多的人贡献自己的力量,为科学技术发展出力 
  13. * 科技站在巨人的肩膀上进步更快!感谢有开源前辈的贡献! 
  14. *********************************************************************/ 
  15. #include <sys/mman.h> /* for mmap and munmap */ 
  16. #include <sys/types.h> /* for open */ 
  17. #include <sys/stat.h> /* for open */ 
  18. #include <fcntl.h>     /* for open */ 
  19. #include <unistd.h>    /* for lseek and write */ 
  20. #include <stdio.h> 
  21.  
  22. int main(int argc, char **argv) 
  23.     int fd; 
  24.     char *mapped_mem, * p; 
  25.     int flength = 1024; 
  26.     void * start_addr = 0; 
  27.  
  28.     fd = open(argv[1], O_RDWR | O_CREAT, S_IRUSR | S_IWUSR); 
  29.     flength = lseek(fd, 1, SEEK_END); 
  30.     write(fd, "\0", 1); /* 在文件最后添加一个空字符,以便下面printf正常工作 */ 
  31.     lseek(fd, 0, SEEK_SET); 
  32.     mapped_mem = mmap(start_addr, flength, PROT_READ,        //允许读 
  33.                       MAP_PRIVATE,       //不允许其它进程访问此内存区域 
  34.                       fd, 0); 
  35.     /* 使用映射区域. */ 
  36.     printf("%s\n", mapped_mem); /* 为了保证这里工作正常,参数传递的文件名最好是一个文本文件 */ 
  37.     close(fd); 
  38.     munmap(mapped_mem, flength); 
  39.     return 0; 

编译运行此程序:
gcc -Wall mmap.c
./a.out text_filename

上面的方法因为用了PROT_READ,所以只能读取文件里的内容,不能修改,如果换成PROT_WRITE就可以修改文件的内容了。又由于 用了MAAP_PRIVATE所以只能此进程使用此内存区域,如果换成MAP_SHARED,则可以被其它进程访问,比如下面的:

  1. #include <sys/mman.h> /* for mmap and munmap */ 
  2. #include <sys/types.h> /* for open */ 
  3. #include <sys/stat.h> /* for open */ 
  4. #include <fcntl.h>     /* for open */ 
  5. #include <unistd.h>    /* for lseek and write */ 
  6. #include <stdio.h> 
  7. #include <string.h> /* for memcpy */ 
  8.  
  9. int main(int argc, char **argv) 
  10.     int fd; 
  11.     char *mapped_mem, * p; 
  12.     int flength = 1024; 
  13.     void * start_addr = 0; 
  14.  
  15.     fd = open(argv[1], O_RDWR | O_CREAT, S_IRUSR | S_IWUSR); 
  16.     flength = lseek(fd, 1, SEEK_END); 
  17.     write(fd, "\0", 1); /* 在文件最后添加一个空字符,以便下面printf正常工作 */ 
  18.     lseek(fd, 0, SEEK_SET); 
  19.     start_addr = 0x80000; 
  20.     mapped_mem = mmap(start_addr, flength, PROT_READ|PROT_WRITE, //允许写入 
  21.                       MAP_SHARED,       //允许其它进程访问此内存区域 
  22.                       fd, 0); 
  23. /* 使用映射区域. */ 
  24.     printf("%s\n", mapped_mem);
  25. /* 为了保证这里工作正常,参数传递的文件名最好是一个文本文 */ 
  26.     while((p = strstr(mapped_mem, "Hello"))) {
  27. /* 此处来修改文件 内容 */ 
  28.         memcpy(p, "Linux", 5); 
  29.         p += 5; 
  30.     } 
  31.     close(fd); 
  32.     munmap(mapped_mem, flength); 
  33.     return 0; 

man -a mmap 看更详细的信息

(flying5)
本站文章除注明转载外,均为本站原创或编译欢迎任何形式的转载,但请务必注明出处,尊重他人劳动,同学习共成长。转载请注明:文章转载自:罗索实验室 [http://www1.rosoo.net/a/201104/11241.html]
本文出处:百度博客 作者:flying5
顶一下
(2)
100%
踩一下
(0)
0%
------分隔线----------------------------
发表评论
请自觉遵守互联网相关的政策法规,严禁发布色情、暴力、反动的言论。
评价:
表情:
用户名: 验证码:点击我更换图片
栏目列表
将本文分享到微信
织梦二维码生成器
推荐内容