存储映射

  • 使一个磁盘文件与存储空间中的一个缓冲区相映射。
  • 当从缓冲区中取数据,就相当于读文件中的相应字节。
  • 将数据存入缓冲区,则相应的字节就自动写入文件。

使用这种方法,首先应通知内核,将一个指定文件映射到存储区域中。这个映射工作可以通过mmap函数来实现。不通过IO。直接操作内存,效率更高。

mmap函数

函数原型

#include <sys/mman.h>

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

参数分析

  • addr : 建立映射区的首地址,由Linux内核指定。使用时,直接传递NULL。
  • length : 映射长度。
  • prot: 映射区权限。
    • PROT_READ:只读。
    • PROT_WRITE:只写。
    • PROT_READ | PROT_WRITE:可读可写。
    • 其它参数不常用,参照手册。
  • flags: 标志位参数(常用于设定更新物理区域、设置共享、创建匿名映射区).
    • MAP_SHARED:会将映射区所做的操作反映到物理设备(磁盘)上。
    • MAP_PRIVATE: 映射区所做的修改不会反映到物理设备。
    • MAP_ANON:匿名映射,不需要已存在的文件进行映射。fd传-1,只能用于亲缘进程间。
  • fd: 用来建立映射区的文件描述符。
  • offset: 起点的偏移量,必须是4K的整数倍。因为映射至少一页,比如5000字节的文件,映射内存也是2页大小,不会正好是5000.

Note

使用MAP_SHARED的时候,要注意打开文件的权限>=映射区权限。因为如果文件没有写权限,映射区有写权限,那么映射区是无法写入文件的,这和MAP_SHARED的目的相反。如是MAP_PRIVATE就没有此要求。

另外,文件打开权限起码要是可读的,如果不可读,那么怎么读取数据映射到内存呢?

返回值

  • 成功调用返回映射的地址。
  • 失败时返回MAP_FAILED,即void * (-1)。设置errno.

munmap函数

函数原型:

#include <sys/mman.h>
int munmap(void *addr, size_t length);

此函数较为简单,释放映射区,首地址为addr,长度为length.

  • 成功的时候返回0.
  • 失败返回-1且置errno。

应用实例

实现进程间的通信,写进程将一份文件映射到内存,并且每秒写入(覆盖写入)不同的字符串,读进程一直去读。

写进程:

struct Person{
char name[30];
int num;
};
int main(int argc, char const* argv[])
{
//打开文件,作为映射
int fd = open("memTest2.txt", O_RDWR);
//int fd = open("memTest2.txt", O_RDWR);
int length = sizeof(struct Person);
ftruncate(fd, length);
printf("fd=%d\n", fd);
//映射
struct Person* mem = (struct Person*)mmap(0, length, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (mem == MAP_FAILED) {
perror("mmap err");
return -1;
}
printf("映射区地址:%0x\n", mem);
int num = 1;
while (1) {
mem->num = num++;
sprintf(mem->name, "I am a Person%03d", mem->num);
sleep(1);
} //释放
munmap(mem, length);
close(fd);
return 0;
}

读进程:

struct Person{
char name[30];
int num;
}; int main(int argc, char const* argv[])
{
//打开文件,作为映射
int fd = open("memTest2.txt", O_RDWR);
int length = sizeof(struct Person);
printf("fd=%d\n", fd);
//映射
struct Person* mem = (struct Person *)mmap(0, length, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if(mem == MAP_FAILED)
{
perror("mmap err");
return -1;
}
printf("映射区地址:%0x\n", mem);
while (1) {
printf("name=%s,num=%d\n", mem->name,mem->num);
sleep(1);
} //释放
munmap(mem, length);
close(fd);
return 0;
}

最新文章

  1. JavaScript 加载动画Canvas 设计
  2. 用orb-slam2跑RGB-D Example中的TUM Dataset
  3. 有关于java反编译工具的使用
  4. WPF学习之路(一) 初识WPF
  5. Mysql 数据库无法删除 41 错误
  6. [Angularjs]视图和路由(三)
  7. 手把手教你去ECSHOP版权 powered by ecshop
  8. DrawerLayout和ActionBarDrawerToggle
  9. SSM框架中常用的注解
  10. 如何用php实现文件上传与显示
  11. Oracle误删数据文件后出现oracle initialization or shutdown in progress解决
  12. L2-006 树的遍历 (25 分)
  13. CS20SI-tensorflow for research笔记: Lecture2
  14. python数据类型之列表类型
  15. mongo的runCommand与集合操作函数的关系
  16. windows安装Redis和客户端
  17. JAVA8给我带了什么——lambda表达
  18. 记录一则FGA审计“A用户对B用户某张表的更新操作”需求
  19. Nginx和PHP上传文件大小的限制
  20. Eclispe中编辑xml配置文件时不会提示也不能自动调整格式

热门文章

  1. Codeforces 1237D. Balanced Playlist
  2. Codeforces 1240C. Paint the Tree
  3. MySQL中的主键约束和外键约束
  4. 【原创】大叔经验分享(61)kudu rebalance报错
  5. luogu题解 P3709 【大爷的字符串题】
  6. 安装多个ORACLE导致多个Oracle HOME的情况!
  7. python WordCloud 实现词云
  8. vue 日常开发小细节
  9. 原创博客&gt;&gt;&gt;解决粘包问题的方法
  10. Linux下计划任务:crontab 命令的权限说明