C语言中的mmap理解,与一个具体的例子

背景:

记录为什么,怎么解决的,前因后果流水账

记录内容来自阅读书籍,《嵌入式C语言自我修养:从芯片、编译器到操作系统》 

章节5.5 mmap的映射区域探秘
 

 

程序执行
    |
 怎么执行?
    |
 可执行文件加载到内存
    |
 怎么加载?
    |
    |---------- 1.常规文件I/O操作。 read/write系统调用接口
    |
    |---------- 2.mmap系统调用。文件映射到进程虚拟空间,对映射区域读写

先说read、write:

    打开文件路径---> 获得fd ---> 得到inode ---> 找到文件在磁盘的位置。然后读写位置。

===========
    |
    |
    |
  实际问题,读写磁盘老是要转动磁盘到某一位置(涉及硬件原理:硬盘的内部结构包括磁头、磁道、扇区、柱面,读写涉及磁头定位等问题)
    |
    |
  如何解决 ?
    |
    |
  linux系统提供磁盘缓冲机制
                |
                |
                |------- 1. 提出分页的概念,用页来缓存磁盘上的普通文件和设备文件
                         2. 每次读写,先看页缓存中是否存在,不存在就把磁盘数据读取到页中
                         3. 页缓存超过阈值,或刷新时间。linux内核把数据写回磁盘。
上面说的是页缓存机制。
       |
       |
   有何问题 ?
       |
       |
但是频繁read/wirte就会读来读取,内核和用户空间数据拷贝次数太多。
       |
       |
   如何优化 ?
       |
       |
   减少内核负担,在用户空间搞个I/O缓冲区,先把内核页缓存读到用户I/O缓存,用户频繁使用时,就直接查看用户的这块I/O空间。(fread/fwrite对read/write的封装)
       |
       |
   有何问题 ?
       |
       |
    减少了系统调用的次数,减少了内核的负担。但是!用户空间多个缓存区,这个增加了次数,负担转移而已,当数据量大,拷贝也的开销依旧存在。
       |
       |     
  如何进一步优化?
       |
       |
  答案:用户空间文件直接映射到进程的虚拟空间
                    |
                    |   
                    |----- 通过mmap, 文件内容和地址一一对应,对映射地址的读写相当于对磁盘文件的读写。


----------------
这个就是mmap由来的前因后果。

 mmap函数:

/*    addr:   映射虚拟内存的起始地址,一般为NULL
 *    length:  映射内存区域大小
 *    prot:    内存保护标志PROT_EXEC, PROT_READ, PROT_WRITE
 *    fd:      要映射的文件
 *    offset:  文件偏移
 **/

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

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

int main(int argc, char *argv[])
{
    int fd;
    int i;
    char *p_map;

    fd = open(argv[1], O_CREAT|O_RDWR|O_TRUNC, 0666);
    write(fd, "", 14);
    p_map = (char*)mmap(NULL, 20, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
    
    if(p_map == MAP_FAILED)
    {
        perror("mmap");
        return -1;
    }
    close(fd);

    if (fd == -1)
    {
        perror("close");
        return -1;
    }

    memcpy(p_map, "hello world_world_world_world!\n", 14);
    sleep(5);
    if(munmap(p_map, 20) == -1)
    {
        perror("munmap");
        return -1;
    }

    return 0;
}

运行:

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值