在本文中,我们主要介绍mmap的原理。
一、传统的读写文件
通常来说,更改一个文件的内容须要如下3个步骤:
过程如图1所示:
假如使用代码来实现里面的过程linux操作系统教程,代码如下:
read(fd, buf, 1024); // 读取文件的内容到buf
... // 修改buf的内容
write(fd, buf, 1024); // 把buf的内容写入到文件
从图1中可以看出,页缓存(pagecache)是读写文件时的中间层,内核使用页缓存与文件的数据块关联上去。所以应用程序读写文件时,实际操作的是页缓存。
二、使用mmap读写文件
从传统读写文件的过程中,我们可以发觉有个地方可以优化:假如可以直接在用户空间读写页缓存,这么就可以免去将页缓存的数据复制到用户空间缓冲区的过程。
这么,有没有这样的技术能实现前面所说的方法呢?答案是肯定的,就是mmap。
使用mmap系统调用可以将用户空间的虚拟显存地址与文件进行映射(绑定),对映射后的虚拟显存地址进行读写操作就仿佛对文件进行读写操作一样。原理如图2所示:
后面我们介绍过,读写文件都须要经过页缓存,所以mmap映射的正是文件的页缓存,而非c盘中的文件本身。因为mmap映射的是文件的页缓存,所以就涉及到同步的问题,即页缓存会在哪些时侯把数据同步到c盘。
Linux内核并不会主动把mmap映射的页缓存同步到c盘,而是须要用户主动触发。同步mmap映射的显存到c盘有4个时机:
推荐视频:
90分钟了解Linux显存构架,numa的优势,slab的实现,vmalloc的原理
为何不推荐做mcu与qt开发,c++linux后台服务器开发很香吗?
学习地址:c/c++linux服务器开发/后台构架师
【文章福利】需要C/C++Linux服务器构架师学习资料加群812855908(资料包括C/C++,Linux,golang技术,内核,Nginx,ZeroMQ,MySQLmmap linux 文件,Redis,fastdfs,MongoDB,ZK,流媒体,CDN,P2Pmmap linux 文件linux系统安装,K8S,Docker,TCP/IP,解释器,DPDK,ffmpeg等)
三、mmap的使用方法
下边我们介绍一下怎样使用mmap,mmap函数的原型如下:
void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);
下边介绍一下mmap函数的各个参数作用:
flags:指定映射的类型,常用的可选值如下:fd:进行映射的文件句柄。offset:文件偏斜量(从文件的何处开始映射)。
介绍完mmap函数的原型后,我们如今通过一个简单的反例介绍如何使用mmap:
int fd = open(filepath, O_RDWR, 0644); // 打开文件
void *addr = mmap(NULL, 8192, PROT_WRITE, MAP_SHARED, fd, 4096); // 对文件进行映射
在里面反例中,我们先通过open函数以可读写的方法打开文件,之后通过mmap函数对文件进行映射,映射的方法如下:
mmap函数会返回映射后的显存地址,我们可以通过此显存地址对文件进行读写操作。我们通过图3展示里面反例在内核中的结构:
四、总结
本文主要介绍了mmap的原理和使用方法,通过本文我们可以晓得,使用mmap对文件进行读写操作时可以降低显存拷贝的次数,而且可以降低系统调用的次数,因而提升对读写文件操作的效率。
因为内核不会主动同步mmap所映射的显存区中的数据,所以在个别特殊的场景下可能会出现数据遗失的情况(如断电)。为了防止数据遗失,在使用mmap的时侯可以在适当时主动调用msync函数来同步映射显存区的数据。