您的位置:首页 > 其它

使用mmap函数进行内核空间和用户空间的共享内存通信

2018-01-22 16:47 337 查看

 用户空间与内核空间的通信方法有很多,如ioctl,procfs,sysfs等。但是,这些方法仅能在用户空间与内核空间之间交互简单的数据。如果要实现大批量数据的传递,比如V4L2协议需要大批量传递图片信息,最好的方法就是共享内存。利用设备驱动模型中的mmap函数,可以很容易实现一个简单的共享内存。本文通过具体实例,介绍一下这种共享内存的实现方法。
        系统调用mmap通常用来将文件映射到内存,以加快该文件的读写速度。当用mmap操作一个设备文件时,可以将设备上的存储区域映射到进程的地址空间,从而以内存读写的方法直接控制设备。如果我们在内核模块里申请了一段内存区域,也可以利用此方法,将这个过程映射到用户空间,以实现内核空间与用户空间之间的共享内存。

 共享内存可以说是最有用的进程间通信方式,也是最快的IPC形式, 因为进程可以直接读写内存,而不需要任何数据的拷贝。对于像管道和消息队列等通信方式,则需要在内核和用户空间进行四次的数据拷贝,而共享内存则只拷贝两次数据: 一次从输入文件到共享内存区,另一次从共享内存区到输出文件。实际上,进程之间在共享内存时,并不总是读写少量数据后就解除映射,有新的通信时,再重新建立共享内存区域。而是保持共享区域,直到通信完毕为止,这样,数据内容一直保存在共享内存中,并没有写回文件。共享内存中的内容往往是在解除映射时才写回文件的。因此,采用共享内存的通信方式效率是非常高的。

传统文件访问

UNIX访问文件的传统方法是用open打开它们, 如果有多个进程访问同一个文件, 则每一个进程在自己的地址空间都包含有该文件的副本,这不必要地浪费了存储空间. 下图说明了两个进程同时读一个文件的同一页的情形. 系统要将该页从磁盘读到高速缓冲区中, 每个进程再执行一个存储器内的复制操作将数据从高速缓冲区读到自己的地址空间.



共享存储映射

现在考虑另一种处理方法: 进程A和进程B都将该页映射到自己的地址空间, 当进程A第一次访问该页中的数据时, 它生成一个缺页中断. 内核此时读入这一页到内存并更新页表使之指向它.以后, 当进程B访问同一页面而出现缺页中断时, 该页已经在内存, 内核只需要将进程B的页表登记项指向次页即可. 如下图所示:



mmap系统调用使得进程之间通过映射同一个普通文件实现共享内存,普通文件被映射到进程地址空间后,进程可以像访问普通内存一样对文件进行访问,不必再调用read和write等。



mmap用户空间

用户空间mmap函数原型

头文件 sys/mman.h

void *mmap(void *start, size_t length, int prot, int flags, int fd, off_t offset);

int munmap(void *start, size_t length);

int msync ( void * addr , size_t len, int flags) 通过调用msync()实现磁盘上文件内容与共享内存区的内容一致

作用:

mmap将一个文件或者其他对象映射进内存,当文件映射到进程后,就可以直接操作这段虚拟地址进行文件的读写等操作。

参数说明:

start:映射区的开始地址

length:映射区的长度

prot:期望的内存保护标志

—-PROT_EXEC //页内容可以被执行

—-PROT_READ //页内容可以被读取

—-PROT_WRITE //页可以被写入

—-PROT_NONE //页不可访问

flags:指定映射对象的类型

—-MAP_FIXED

—-MAP_SHARED 与其它所有映射这个对象的进程共享映射空间

—-MAP_PRIVATE 建立一个写入时拷贝的私有映射。内存区域的写入不会影响到原文件

—-MAP_ANONYMOUS 匿名映射,映射区不与任何文件关联

fd:如果MAP_ANONYMOUS被设定,为了兼容问题,其值应为-1

offset:被映射对象内容的起点
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: