c++ mmap写入速度_Linux系统编程_用mmap+数组的方式修改数据文件

正文开始前,先聊点非技术的东西,推荐2本生动有趣的书:

  • 《经济学原理 宏观经济学》,曼昆,豆瓣评分9.3,4945人评价
  • 《经济学原理 微观经济学》,曼昆,豆瓣评分9.6,1879人评价

我想看这两本书原因是:Joel on Software 在一篇 给计算机系学生 的忠告文章里说,毕业之前你一定要修一门经济学课程,Joel( stackoverflow 的创始人 ) 的话在我心里有很重的分量,我愿意接受他的建议,甚至认为自己 应该在高中时 就阅读上面2本书。

这两本书在豆瓣上的评价极高:

一看到《经济学原理》这样的书名,我会立即把它归为异次元一类,碰都不会去碰,别说读它了,自从大学毕业后,对于任何此类教科书,我会毫不客气地说,滚!
这种情绪的对立既包含了对中国教育制度的控诉,又体现了对死读书无法改变命运的残酷现实的无奈。
工作约7到8年后,自我体会到和社会的逐渐脱节,这里不止是因为工作环境的隔离性和社交圈的狭窄,还有自身知识量的乏馈,光是义务教育和本科教育所建立的知识结构显然已经无法支撑起我的求知欲所对应的飞速发展的社会万物,可是学习从何开始呢?

话说到这里,志同道合的人应该知道怎么做了,我就不再讲废话了,下面回归到技术上。

以下是正文:

一、背景知识

mmap()系统调用在调用进程的虚拟地址空间中创建一个新内存映射( memory mappings ),映射分为两种:

  1. 文件映射( File mapping ):文件映射将一个文件的一部分直接映射到调用进程的虚拟内存中。一旦一个文件被映射之后就可以通过在相应的内存区域中操作字节来访问文件内容了。映射的分页会在需要的时候从文件中(自动)加载。这种映射也被称为基于文件的映射( file-based mapping )或内存映射文件( memory-mapped file )。

  2. 匿名映射( Anonymous mapping ):匿名映射没有对应的文件,这种映射的分页会被初始化为0。

我们可以使某个磁盘文件的内容看起来就像是内存中的一个数组。如果文件的内容是由读多条 C 语言结构体描述的记录构成的话,你就可以通过访问结构体数组来更新文件的内容了。

1. 创建映射: mmap()

mmap()系统调用在调用进程的虚拟地址空间中创建一个新映射,如果是文件映射的话,是通过文件描述符和文件关联在一起:

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

成功时 mmap() 会返回新映射的起始地址。发生错误时 mmap( )会返回 MAP_FAILED。

参数:

  • addr,用去指定内存区域的起始地址,为了可移植性,一般设为 NULL, 表示由系统自动决定内存区域的起始地址。不管采用何种方式,内核会选择一个不与任何既有映射冲突的地址。

  • len, 映射区域的长度。

  • prot,映射区域的访问权限,可选项包括 READ/WRITE/EXEC/NONE。

  • flags, 映射区域的可见性:

    • 私有映射(MAP_PRIVATE):在映射内容上发生的变更对其他进程不可见,对于文件映射来讲,变更将不会在底层文件上发生。
    • 共享映射(MAP_SHARED):在映射内容上发生的变更对所有共享同一个映射的其他进程都可见,对于文件映射来讲,变更将会发生在底层的文件上。
  • fd, 被映射的文件的文件描述符。

  • offset, 从该偏移位置开始映射。

更多知识点:

9903064d65272b2e09ec4637c31a5b2a.png

  • 在打开描述符fd引用的文件时必须要具备与prot和flags参数值匹配的权限。

  • offset参数指定了从文件区域中的哪个字节开始映射,它必须是系统分页大小的倍数。

  • 一旦mmap()被调用之后就能够关闭文件描述符了,而不会对映射产生任何影响。

  • 在Linux上,一个文件映射的分页会在首次被访问时被映射进内存。

  • 除了普通的磁盘文件,使用 mmap() 还能够映射各种真实和虚拟设备的内容,如硬盘、光盘以及/dev/mem。

2. 同步映射区域:msync()

msync() 系统调用让应用程序能够显式地 在某种程度上 控制何时完成共享映射与映射文件之间的同步。

$ man msync
SYNOPSIS
    #include 
       int msync(void *addr, size_t length, int flags);
DESCRIPTION
       msync()  flushes  changes made to the in-core copy of a file that was mapped into memory using mmap(2) back to the filesystem.

参数:

  • addr和length参数指定了需同步的内存区域的起始地址和大小。

  • flags 的可取值:

    • MS_SYNC,执行一个同步的文件写入。会阻塞直到内存区域中所有被修改过的分页被写入到磁盘为止。
    • MS_ASYNC,执行一个异步的文件写入,会立即返回。内存区域中被修改过的分页会在后面某个时刻被写入磁盘并立即对在相应文件区域中执行 read() 的其他进程可见。
    • MS_INVALIDATE,使映射数据的缓存副本失效。其结果是其他进程对文件做出的所有更新将会在内存区域中可见。

更多知识点:

  • 如果映射是私有的,那么不修改被映射的文件。

  • 与其他内存映射函数一样,地址必须与页边界对齐。

  • MS_ASYNC 不保证何时写入,因为在后台运行的 IO elevator 算法试图通过合并和排序写入来最大程度地提高效率,以最大程度地提高 IO 的吞吐量。

二、演示 demo

1. 分解代码

定义数据类型:

typedef struct {
    int integer;
    char string[24];
} RECORD;

构造数据文件 records.dat:

fp = fopen("records.dat","w+");
for(i=0; i    record.integer = i;
    sprintf(record.string,"RECORD-%d",i);
    fwrite(&record,sizeof(record),1,fp);
}

映射文件 records.dat:

f = open("records.dat",O_RDWR);
mapped = (RECORD *)mmap(0, NRECORDS*sizeof(record), 
                        PROT_READ|PROT_WRITE, MAP_SHARED, f, 0);

通过结构体数组修改数据( RECORD-43->RECORD-243 ):

mapped[43].integer = 243;
sprintf(mapped[43].string,"RECORD-%d",mapped[43].integer);
msync((void *)mapped, NRECORDS*sizeof(record), MS_ASYNC);

清理现场:

munmap((void *)mapped, NRECORDS*sizeof(record));
close(f);

2. 运行效果

$ gcc mmap.c -o mmap
$ ./mmap
$ ls
mmap  mmap.c  records.dat
$ strings records.dat
RECORD-0
RECORD-1
RECORD-2
...
RECORD-42
RECORD-243
RECORD-44
...

可以看到:RECORD-43 被成功修改为 RECORD-243。

演示的 demo 就这么简单,却需要如此多的背景知识,甚至还有大量的细节没在文中披露,有需要时再深入讲解吧。

三、相关参考

  • 《Linux/Unix 系统编程手册-第49章 内存映射》
  • 《Linux程序设计-第3章 文件操作》
  • 《Unix 环境高级编程-第14章节 14.8-存储映射I/O》
  • LWN: R.I.P. pdflush
  • Stack Overflow: msync(MS_ASYNC) flush order

你和我各有一个苹果,如果我们交换苹果的话,我们还是只有一个苹果。但当你和我各有一个想法,我们交换想法的话,我们就都有两个想法了。如果你也对 嵌入式系统和开源软件 感兴趣,并且想和更多人互相交流学习的话,请关注我的公众号:嵌入式系统砖家,一起来学习吧,关注或转发都是是对作者最大的支持,谢谢大家,祝工作顺利~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/422281.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

太极软件qn的代码_多版本QQ内置qn、qx模块

软件名称:QQ版本号:1362、1392、1558版本:8.3.0、8.3.5、8.4.18安装包大小:81.93m、88.64m、100.93m简介:分别是830、835、8418这三个版本的QQ,只内置qn、qx模块,可以实现无需root,无…

asp.net 导入excel显示进度

这几天在做个导入excel的上传页面,由于数据量太大,要显示个进度条,本人不懂jquery,所以百度完再经过调整之后完成了,如果告诉别人只是为了显示个进度条而弄个多线程,还要根据session的机制模拟一个具有sess…

element form自定义校验_SpringBoot分组校验及自定义校验注解

前言在日常的开发中,参数校验是非常重要的一个环节,严格参数校验会减少很多出bug的概率,增加接口的安全性。在此之前写过一篇SpringBoot统一参数校验主要介绍了一些简单的校验方法。而这篇则是介绍一些进阶的校验方式。比如说:在某…

前端学习(526):等分布局

<!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>等分布局</title><style>.col1{backgro…

前端学习(527):等分布局第二种方案

<!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>等分布局</title><style>.parent{width…

c语言 feof_C语言 技能提升 系列文章(六)文件操作

C语言除了提供open()/ read()/ write()/ close() 这些基本的操作以外&#xff0c;还提供了下面几个非常有用的API。// 删除指定的文件int remove ( const char * filename ); // 重命名指定的文件int rename ( const char * oldname, const char * newname );// 以“wb”模式打…

谷歌(Google)是怎样对待离世的Google员工的?

日期&#xff1a;2012-8-10 来源&#xff1a;GBin1.com 如果提起谷歌的福利来说&#xff0c;大家肯定首先想到免费的食品和理发&#xff0c;及其独立的医疗服务&#xff0c;或者超棒的食堂和大厨等等。但是你是否知道谷歌是怎么对待死亡的Google员工的呢&#xff1f; 和Google…

前端学习(529):等分布局存在间距得实现得解决方案

<!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>等分布局</title><style>.parent{heigh…

easyUI 添加CheckBox选择到DataGrid

author YHC 这个教程向你展示如何放置一个checkbox 列到datagrid,这个复选框用户将可以选择 选中/取消选中 datagrid行数据. 查看 Demo 添加一个checkbox 列我们仅仅需要添加一个列的checkbox 属性设置它为true,代码看上去就像这些: <table id"tt" title"Che…

前端学习(530):等分布局得间距方案第二种方式

<!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>等分布局</title><style>.parent{width…

knn k的选取_KNN - 初窥K近邻算法

1>算法概述KNN: 全名K-NearestNeighbor&#xff0c;K近邻算法&#xff0c;简单讲就是每个样本都可以用最接近的k个邻居表示&#xff0c;或者说共享同一个标签。KNN是一种分类(classification)算法&#xff0c;它输入基于实例的学习&#xff08;instance-based learning&…

前端学习(535):多列布局2

<!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>css多列布局</title><style>.parent{co…

前端学习(536):多列布局3列得间距

<!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>css多列布局</title><style>.parent{co…

scp会覆盖同名文件吗_你会Hypermesh一键式完成几何文件到求解文件的输出吗?

前不久&#xff0c;我在仿真秀APP更新了2篇Hypermesh二次开发的文章&#xff0c;介绍了《Hypermesh二次开发之电子产品跌落全流程开发讲解》和《前处理软件Hypermesh二次开发如何从入门到精通》&#xff1b;同步推出了《Hypermesh 二次开发高级培训11讲》线上视频课程&#xff…

前端学习(537):多列布局4横跨多列

<!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>css多列布局</title><style>.parent,.p…