Chinaunix

标题: mmap系统调用共享内存 [打印本页]

作者: pmdxx    时间: 2008-08-17 14:28
标题: mmap系统调用共享内存

       
       
       
       
       
       
[color="#000000"]参考资料:
Linux
C库函数详解词典
[color="#000000"]http://www.ibm.com/developerworks/cn/linux/l-ipc/part5/index1.html
[color="#000000"]文章主要来自IBM[color="#000000"]/developerworks
                    mmap系统调用共享内存
mmap()系统调用使得进程之间通过映射同一个普通文件实现共享内存。普
通文件被映射到进程地址空间后,进程可以向访问普通内存一样对文件进
行访问,不必再调用read(),write()等操作。
注:实际上,mmap()系统调用并不是完全为了用于共享内存而设计的。它
本身提供了不同于一般对普通文件的访问方式,进程可以像读写内存一样
对普通文件的操作。而Posix或系统V的共享内存IPC则纯粹用于共享目的
,当然mmap()实现共享内存也是其主要应用之一。
1、建立内存映射函数
mmap()
功能:用来将某个文件内容映射到内存中,对该内存区域的访问即是直接
对该文件内容的读写。调用成功返回映射区的内存起始地址,进程可直接
操作起始
地址为该值的有效地址 ,否则返回-1。
#include
#include
void
*mmap(void *addr/*指定文件应被映射
到进程空间的起始地址,一
般被指定一个空指针,此时选择起始地址的任务留给内核来完成*/
,
size_t len/*映射到调用进程地址空间的字节数,它
从被映射文件开头
offset个字节开始算起*/
,
int prot/*指定共享内存的访问权限。可取如下几个值的或:
PROT_READ(可读)
,
PROT_WRITE
(可写),
PROT_EXEC
(可执行),
PROT_NONE(不可访问)。*/
,
int flags/*flags由以下几个常值指定:MAP_SHARED
, MAP_PRIVATE ,
MAP_FIXED,其中,MAP_SHARED
, MAP_PRIVATE必选其一,而MAP_FIXED则不推荐使用*/
,
int
fd/*fd为即将映射到进程空间的文件描述字,一般由open()返回,
同时,fd可以指定为-1,此时须指定flags参数中的MAP_ANON,表明进

的是匿名映射(不涉及具体的文件名,避免了文件的创建及打开,很显然
只能用于具有亲缘关系的进程间通信)*/
,
off_t offset)/*一般设为0,表示从文件头开始映射*/
2、系统调用mmap()用于共享内存的两种方式
1)、使用普通文件提供的内存映射:适用于任何进程之间;
此时,需要
打开或创建一个文件,然后再调用mmap();典型调用代码如下:
fd=open(name, flag, mode);
if(fd
        ...
2)、使用特殊文件提供匿名内存映射:适用于具有亲缘关系的进程之间;
由于父子进程特殊的亲缘关系,在父进程中先调用mmap(),然后调用
fork()。那么在调用fork()之后,子进程继承父进程匿名映射后的地址空
间,同样也继承mmap()返回的地址,这样,父子进程就可以通过映射区域
进行通信了。注意,这里不是一般的继承关系。一般来说,子进程单独维
护从父进程
继承下来的一些变量。而mmap()返回的地址,却由父子进程共同维护。
对于具有亲缘关系的进程实现共享内存最好的方式应该是采用匿名内存映
射的方式。此时,不必指定具体的文件,只要设置相应的标志即可
3、解除内存映射函数
munmap
用来取消参数start所指向的内存起始地址,成功返回0,失败返回-1
#include
#include
int
munmap( void * start, size_t len )
start
是调用mmap()时返回的地址,len是映射区的大小。当进程结束或使
用exec相关函数来执行其他程序时,映射内存会自动解除,但关闭相应的
文件描述符不会解除映射。当映射关系解除后,对原来映射地址的访问将
导致段错误发生。
4、刷新变化函数
msync
功能:进程在映射空间的对共享内容的改变并不直接写回到磁盘文件中,
往往在调用munmap()后才执行该操作。可以通过调用msync()实现磁盘上
文件内容与共享内存区的内容一致。成功返回0,失败返回-1,定义如下:
#include
#include
int
msync ( void * addr /*刷新的地址*/
,
size_t len/*大小*/
,
int flags) /标志和权限/
5、在使用过程中应该注意的地方:
1)、
最终被映射文件的内容的长度不会超过文件本身的初始大小,即映
射不能改变文件的大小;
2)、
可以用于进程通信的有效地址空间大小大体上受限于被映射文件的
大小,但不完全受限于文件大小。
注:在linux中,内存的保护是以页为基本单位的,即使被映射文件只有一
个字节大小,内核也会为映射分配一个页面大小的内存。当被映射文件小
于一个页面
大小时,进程可以对从mmap()返回地址开始的一个页面大小进
行访问,而不会出错;但是,如果对一个页面以外的地址空间进行访问,
则导致错误发生,后面
将进一步描述。因此,可用于进程间通信的有效地
址空间大小不会超过文件大小及一个页面大小的和。
3)、
文件一旦被映射后,调用mmap()的进程对返回地址的访问是对某一
内存区域的访问,暂时脱离了磁盘上文件的影响。所有对mmap()返回地址
空间的操作
只在内存中有意义,只有在调用了munmap()后或者msync()
时,才把内存中的相应内容写回磁盘文件,所写内容仍然不能超过文件的
大小。
结论:采用系统调用mmap()实现进程间通信是很方便的,在应用层上接口
非常简洁。而内部实现机制区涉及到了linux存储管理以及文件系统等方面
的内容,可以参考一下相关重要数据结构来加深理解。


本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u2/74012/showart_1132630.html




欢迎光临 Chinaunix (http://bbs.chinaunix.net/) Powered by Discuz! X3.2