mmap共享存储映射(存储I/O映射)系列详解

mmap共享存储映射又称为存储I/O映射,是Unix**共享内存**概念中的一种。
在Unix进程间通信中,大致有

1. 管道                  pipe(),用于父子进程间通信(不考虑传递描述符)
2. FIFO(有名管道)       非父子进程也能使用,以文件打通
3. 文件                  文件操作,效率可想而知
4. 本地套接字             最稳定,也最复杂.套接字采用Unix域
5. 共享内存               传递最快,消耗最小,传递数据过程不涉及系统调用
6. 信号                  数据固定且短小

其中,共享内存是IPC(进程间通信)中最快的,一旦共享内存映射到共享它的进程的地址空间中,这些进程的数据传递就不再涉及内核,因为它会以指针的方式读写内存,不涉及系统级调用。

一、管道与共享存储映射对比

首先,我们简单的对比 管道与共享存储映射。

管道

管道相关还可以看这篇文章:
https://blog.csdn.net/qq_36359022/article/details/79795218

请看下图,左图描述了fork()通过pipe()开启管道的示意图,假设父进程从文件A中读取数据并通过管道传递给子进程,由子进程执行某些操作后写入文件B。
首先,进程的数据区位于0-3G的虚拟地址空间中,3G-4G为内核区,注意,文件A和文件B并不是存储在内核区,这里只是示意。并且,本次父子进程完全按照最早期Unix的实现讲解,也就是说父子进程完全独立的空间,不涉及到后来的写时复制等技术。

(1)父进程通过系统调用read()从文件A读取数据的过程中,父进程的状态切换到内核态,读取数据并保存到父进程空间中的buf中,再切换回用户态。这里发生了第一次数据的拷贝
(2)父进程通过系统调用write()将读取的数据从buf中拷贝到管道的过程中,父进程状态切换到内核态,向管道写入数据,再切换回用户态。这里发生第二次数据拷贝。
(3)子进程通过系统调用read()从管道读取数据的过程中,子进程状态切换到内核态,读取数据并保存到子进程空间中的buf中,再切换回用户态。这里发生第三次数据拷贝。
(4)子进程通过系统调用write()将读取的数据从buf中拷贝到文件B的过程中,子进程状态切换到内核态,向文件B写入数据,再切换回用户态。这里发生第四次数据拷贝。

可以看到,这里发生了四次数据拷贝都是再内核与某个进程间进行的,这种开销往往更大(比存粹在内核中或单个进程内复制数据的开销更大)

因此,通过管道进行数据传递在编程上简单,而实际开销是作为一个追求极致效率的程序员所不允许的。接着我们来看看共享存储映射的开销是怎样的呢?

共享存储映射(存储I/O映射)

请看下图,该图描述了父进程使用mmap()使用共享存储映射,fork()后,fork会对内存映射文件进行特殊处理,也就是父进程在调用fork()之前创建的内存映射关系由子进程共享。该方式只有两次系统系统调用。而之前有四次调用
因此࿰

  • 32
    点赞
  • 94
    收藏
    觉得还不错? 一键收藏
  • 9
    评论
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值