Day06(下) Liunx高级系统设计7-磁盘映射与共享内存

磁盘映射MMAP

概述

存储映射 I/O (Memory-mapped I/O) 使一个磁盘文件与存储空间中的一个缓冲区相
映射。于是当从缓冲区中取数据,就相当于读文件中的相应字节。于此类似,将数据存
入缓冲区,则相应的字节就自动写入文件。这样,就可在不适用 read write 函数
的情况下,使用地址(指针)完成 I/O 操作。 使用存储映射这种方法,首先应通知内
核,将一个指定文件映射到存储区域中。这个映射工作可以通过 mmap 函数来实现。

与文件读取的区别(了解)

首先简单的回顾一下常规文件系统操作(调用 read/fread 等类函数)中,函数的调用
过程:
1 、进程发起读文件请求。
2 、内核通过查找进程文件符表,定位到内核已打开文件集上的文件信息,从而找到此
文件的 inode( 存储文件元信息的区域 , 中文名索引节点 )
3 inode address_space( 地址空间 ) 上查找要请求的文件页是否已经缓存在页缓存
中。如果存在,则直接返回这片文件页的内容。
4 、如果不存在,则通过 inode 定位到文件磁盘地址,将数据从磁盘复制到页缓存。之后
再次发起读页面过程,进而将页缓存中的数据发给用户进程。
总结来说,常规文件操作为了提高读写效率和保护磁盘,使用了页缓存机制。这样造成
读文件时需要先将文件页从磁盘拷贝到页缓存中,由于页缓存处在内核空间,不能被用
户进程直接寻址,所以还需要将页缓存中数据页再次拷贝到内存对应的用户空间中。这
样,通过了两次数据拷贝过程,才能完成进程对文件内容的获取任务。写操作也是一
样,待写入的 buffer 在内核空间不能直接访问,必须要先拷贝至内核空间对应的主存,
再写回磁盘中(延迟写回),也是需要两次数据拷贝。
而使用 mmap 操作文件中,创建新的虚拟内存区域和建立文件磁盘地址和虚拟内存区域映
射这两步,没有任何文件拷贝操作。而之后访问数据时发现内存中并无数据而发起的缺
页异常过程,可以通过已经建立好的映射关系,只使用一次数据拷贝,就从磁盘中将数
据传入内存的用户空间中,供进程使用。
总而言之,常规文件操作需要从磁盘到页缓存再到用户主存的两次数据拷贝。而 mmap
控文件,只需要从磁盘到用户主存的一次数据拷贝过程。
mmap 效率更高

相关函数

mmap 函数
作用:
建立映射区
语法
所需头文件
#include <sys/mman.h>
函数
void *mmap(void *addr, size_t length, int prot, int flags,int fd,
off_t offset);
参数 :
        addr 内核创建映射的地址,填 NULL, 由内核自己选取地址
        length 长度 要申请的映射区的长度
        prot 权限
                PROT_READ 可读
                PROT_WRITE 可写
        flags 标志位
                MAP_SHARED 共享的 -- 对映射区的修改会影响源文件
                MAP_PRIVATE 私有的
        fd 文件描述符 需要打开一个文件
        offset 指定一个偏移位置 ,从该位置开始映射
返回值
        成功 返回映射区的首地址
        失败 返回 MAP_FAILED ((void *) -1)
munmap 函数
作用:
释放映射区
语法:
所需头文件
        #include <sys/mman.h>
函数
        int munmap(void *addr, size_t length)
参数 :
        addr 映射区的首地址
        length 映射区的长度
返回值
        成功 返回 0
        失败 返回 -1
truncate 函数
作用
会将参数 path 指定的文件大小改为参数 length 指定的大小 . 如果原来的文件大小比参数length , 则超过的部分会被删去 .
函数
所需头文件
#include <unistd.h>
#include <sys/types.h>
函数
        int truncate(const char *path, off_t length);
参数 :
        path 要拓展的文件
        length 要拓展的长度
使用步骤
1, 打开文件
2, 指定文件大小
3, 建立映射
4, 释放映射区
示例
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <unistd.h>
#include <string.h>
int main(int argc, char const *argv[])
{
    // 1、通过open打开文件
    int fd = open("tmp", O_RDWR | O_CREAT, 0666);
    if (fd < 0)
    {
        perror("open");
        return 0;
    }
    // 2、拓展文件大小
    truncate("tmp", 16);
    // 3、mmap建立映射
    char *buf = (char *)mmap(NULL, 16, PROT_READ | PROT_WRITE, MAP_SHARED,
                             fd, 0);
    // 4、使用内存区域,读
    printf("buf=%s\n", buf);
    printf("buf=%s\n", buf);
    // 4、使用内存区域,写
    // strcpy(buf, "hello mmap");
    // 5、断开映射
    munmap(buf, 16);
    close(fd);
    return 0;
}

共享内存

概述

共享内存允许两个或者多个进程共享给定的存储区域。
物理内存 : 电脑物理内存就是指的内存条
虚拟内存 : 是系统默认在 C 盘划分的一部分磁盘空间临时存储数据用的

特点

1 、共享内存是进程间共享数据的一种最快的方法。 一个进程向共享的内存区域写入了
数据,共享这个内存区域的所有进程就可以立刻看到其中的内容 .
2 、使用共享内存要注意的是多个进程之间对一个给定存储区访问的互斥。 若一个进程
正在向共享内存区写数据,则在它做完这一步操作前,别的进程不应当去读、写这些数

ubuntu 部分版本中共享内存限制值如下

共享存储区的最小字节数: 1
共享存储区的最大字节数: 32M
共享存储区的最大个数: 4096
每个进程最多能映射的共享存储区的个数: 4096

共享内存命令

查看共享内存 ipcs -m
删除共享内存 ipcrm -m shmid

相关函数

shmget函数

作用
创建或打开一块共享内存区 , 获得一个共享存储标识符
函数:
所需头文件
        #include <sys/ipc.h>
        #include <sys/shm.h>
函数
        int shmget(key_t key, size_t size, int shmflg);
参数
        key:IPC 键值 ( 进程间通讯键值 )
        size:该共享存储段的长度 ( 字节 )
        shmflg:标识函数的行为及共享内存的权限。
                IPC_CREAT:创建, 如果不存在就创建
                IPC_EXCL:如果已经存在则返回失败
                位或权限位:共享内存位或权限位后可以设置共享内存的访问权限,格式和open函数的 mode_t 一样 , 但可执行权限未使用。
返回值 :
        成功:返回共享内存标识符。
        失败:返回-1
shmat 函数
作用:
建立进程和物理内存的映射
函数
        #include <sys/types.h>
        #include <sys/shm.h>
        void *shmat(int shmid, const void *shmaddr,int shmflg);
参数 :
        shmid:共享内存标识符。
        shmaddr:共享内存映射地址 ( 若为 NULL 则由系 统自动指定 ) ,推荐使用NULL。
        shmflg:共享内存段的访问权限和映射条件
                0:共享内存具有可读可写权限。
                SHM_RDONLY:只读。
                SHM_RND:(shmaddr 非空时才有效)没有指定 SHM_RND 则此段连接到shmaddr 所指定的地址上 (shmaddr 必需页对齐 )
                指定了 SHM_RND 则此段连接到 shmaddr- shmaddr%SHMLBA 所表示的地址上。
返回值:
        成功:返回共享内存段映射地址
        失败:返回 -1
注意 :
shmat 函数使用的时候第二个和第三个参数一般设为 NULL 0, 即系统自动指定共享内存地址, 并且共享内存可读可写
shmdt 函数
作用
将共享内存和当前进程分离 ( 仅仅是断开本进程与共享内存的联系 , 并不删除共享内
)
语法
所需头文件
        #include <sys/types.h>
        #include <sys/shm.h>
函数
        int shmdt(const void *shmaddr);
参数:
        shmaddr:共享内存映射地址。
返回值:
        成功返回 0
        失败返回 -1
shmctl 函数
作用
共享内存空间的控制。
函数
        #include <sys/ipc.h>
        #include <sys/shm.h>
        int shmctl(int shmid, int cmd, struct shmid_ds *buf);
参数:
        shmid:共享内存标识符。
        cmd:函数功能的控制。
                IPC_RMID:删除。
                IPC_SET:设置 shmid_ds 参数。
                IPC_STAT:保存 shmid_ds 参数。
        SHM_LOCK:锁定共享内存段 ( 超级用户 )
        SHM_UNLOCK:解锁共享内存段。
buf shmid_ds 数据类型的地址,用来存放或修改共享内存的属性。
返回值:
        成功返回 0
        失败返回 -1
注意:
SHM_LOCK 用于锁定内存,禁止内存交换。并不代表共享内存被锁定后禁止其它进程访问。其真正的意义是:被锁定的内存不允许被交换到虚拟内存中。这样做的优势在于让共享内存一直处于内存中,从而提高程序性能

使用步骤

1.获取唯一key值

2.获取共享内存标识符

3.建立共享内存映射

4.操作映射

        1.读

        2.写

5.释放映射

示例

#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <string.h>
int main(int argc, char const *argv[])
{
    // 1、获取唯一的key值
    key_t key = ftok("/", 2023);
    // 2、根据唯一的key的共享内存标识(分配物理内存)
    int shm_id = shmget(key, 32, IPC_CREAT | 0666);
    printf("shm_id=%d\n", shm_id);
    // 3、建立进程和物理内存的映射
    char *p = (char *)shmat(shm_id, NULL, 0);
    // 4,操作映射,写
    strcpy(p, "hello shm");
    // 4,操作映射,读
    //  printf("%s\n",p);
    //  5、断开进程和物理内存的映射
    shmdt(p);
    return 0;
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

使用JLink仿真器实现调试打印的N种方法

方法一&#xff1a;使用MCU的串口 这是最古老也是最简单的方法。 电脑上面插一个USB转TTL&#xff0c;然后与MCU的UART_RX/UART_TX/GND连接起来。PC端再打开一个串口调试助手。两边的波特率一致&#xff0c;就可以收到MCU发过来的打印信息了。 方法二&#xff1a;使用JLink仿…

10天玩转Python第2天:python判断语句基础示例全面详解与代码练习

目录 1.课程之前1.1 复习和反馈1.2 作业1.3 今日内容1.4 字符串格式化的补充1.5 运算符1.5.1 逻辑运算符1.5.2 赋值运算符1.5.3 运算符优先 2.判断2.1 if 的基本结构2.1.1 基本语法2.1.2 代码案例2.1.3 练习 2.2 if else 结构2.2.1 基本语法2.2.2 代码案例2.2.3 练习 2.3 if 和…

java--BigDecimal

1.BigDecimal 用于解决浮点型运算时&#xff0c;出现结果失真的问题 2.BigDecimal的常见构造器、常用方法

如何使用unittest批量管理Python接口自动化测试用例?

我们日常项目中的接口测试案例肯定不止一个&#xff0c;当案例越来越多时我们如何管理这些批量案例&#xff1f;如何保证案例不重复&#xff1f;如果案例非常多&#xff08;成百上千&#xff0c;甚至更多&#xff09;时如何保证案例执行的效率&#xff1f;如何做&#xff08;批…

Vmware突然无法获取IP(二)

一 测试环境 宿主机&#xff1a; window10Vmware 17 proUbuntu 18.04虚拟机中 二 问题 之前虚拟机可以正常使用。过程中&#xff0c;安装了docker&#xff08;不确定是否和这个有关系&#xff09;第二天开启虚拟机时&#xff0c;发现网口为down的状态。将网口up后&#xff0…

聊聊跨进程共享内存的内部工作原理

在 Linux 系统的进程虚拟内存中&#xff0c;一个重要的特性就是不同进程的地址空间是隔离的。A 进程的地址 0x4000 和 B 进程的 0x4000 之间没有任何关系。这样确确实实是让各个进程的运行时互相之间的影响降到了最低。某个进程有 bug 也只能自己崩溃&#xff0c;不会影响其它进…

vector类

> 作者简介&#xff1a;დ旧言~&#xff0c;目前大二&#xff0c;现在学习Java&#xff0c;c&#xff0c;c&#xff0c;Python等 > 座右铭&#xff1a;松树千年终是朽&#xff0c;槿花一日自为荣。 > 目标&#xff1a;熟悉vector库 > 毒鸡汤&#xff1a;从人生低谷…

【交流】PHP生成唯一邀请码

目录 前言&#xff1a; 1.随机生成&#xff0c;核对user表是否已存在 代码&#xff1a; 解析&#xff1a; 缺点&#xff1a; 2.建表建库&#xff0c;每次从表中随机抽取一条&#xff0c;用完时扩充 表结构 表视图 代码 解析 缺点 结论&#xff1a; 前言&#xff1a; …

Amazon 亚马逊内推

点击关注公众号&#xff0c;分享 WLB、大厂内推&#xff0c;面经、热点新闻&#xff0c;可内推公司90&#xff0c;累计帮助8000 靠谱的内推君 专注于WLB、大厂精选内推&#xff0c;助力每位粉丝拿到满意的Offer&#xff01; 公司简述 亚马逊公司&#xff08;Amazon&#xff…

基于单片机远程温控检测系统

**单片机设计介绍&#xff0c;基于单片机远程温控检测系统&#xff08;含上位机&#xff09; 文章目录 一 概要二、功能设计设计思路 三、 软件设计原理图 五、 程序六、 文章目录 一 概要 基于单片机的远程温控检测系统可以用于远程监测和控制温度&#xff0c;实现远程温度监…

UDP报文格式详解

✏️✏️✏️各位看官好&#xff0c;今天给大家分享的是 传输层的另外一个重点协议——UDP。 清风的CSDN博客 &#x1f6e9;️&#x1f6e9;️&#x1f6e9;️希望我的文章能对你有所帮助&#xff0c;有不足的地方还请各位看官多多指教&#xff0c;大家一起学习交流&#xff0…

江苏中服产业党总支一行莅临蓝海创意云参观交流

12月5日上午&#xff0c;江苏中服产业党总支及直播产业“两新”党支部一行莅临蓝海创意云参观交流&#xff0c;蓝海创意云相关领导热情接待&#xff0c;双方就直播业务进行了深度沟通&#xff0c;未来将携手合作共同推动直播产业的创新发展。 在蓝海创意云一楼展厅&#xff0c;…

2024年网络安全竞赛-网站渗透

网站渗透 (一)拓扑图 1.使用渗透机对服务器信息收集,并将服务器中网站服务端口号作为flag提交; 使用nmap工具对靶机进行信息收集 2.使用渗透机对服务器信息收集,将网站的名称作为flag提交; 访问页面即可 3.使用渗透机对服务器渗透,将可渗透页面的名称作为flag提交…

【计算机网络】HTTP响应报文Cookie原理

目录 HTTP响应报文格式 一. 状态行 状态码与状态码描述 二. 响应头 Cookie原理 一. 前因 二. Cookie的状态管理 结束语 HTTP响应报文格式 HTTP响应报文分为四部分 状态行&#xff1a;包含三部分&#xff1a;协议版本&#xff0c;状态码&#xff0c;状态码描述响应头&a…

3-Mybatis

文章目录 项目源码地址Mybatis概述什么是Mybatis&#xff1f;Mybatis导入知识补充数据持久化持久层 第一个Mybatis程序&#xff1a;数据的增删改查查项目名称创建环境编写代码1、目录结构2、核心配置文件&#xff1a;resources/mybatis-config.xml3、mybatis工具类&#xff1a;…

AtCoder ABC周赛2023 11/4 (Sat) E题题解

目录 原题截图&#xff1a; 原题翻译 题目大意&#xff1a; 主要思路&#xff1a; 代码&#xff1a; 原题截图&#xff1a; 原题翻译 题目大意&#xff1a; 给你一个数组&#xff0c;给你一个公式&#xff0c;让你选k个元素&#xff0c;用公式算出最终得分。 主要思路&am…

【论文精读】GAIA: A Benchmark for General AI Assistants

GAIA: A Benchmark for General AI Assistants 前言Abstract1 Introduction2 Related work3 GAIA3.1 A convenient yet challenging benchmark for general AI assistants3.2 Evaluation3.3 Composition of GAIA3.4 Building and extending GAIA 4 LLMs results on GAIA5 Discu…

堆排序算法及实现

1、堆排序定义 堆是一棵顺序存储的完全二叉树。 其中每个结点的关键字都不大于其孩子结点的关键字&#xff0c;这样的堆称为小根堆。其中每个结点的关键字都不小于其孩子结点的关键字&#xff0c;这样的堆称为大根堆。 举例来说&#xff0c;对于n个元素的序列{R0, R1, ... ,…

重温经典struts1之常用标签

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 前言 上一篇&#xff0c;我们学习了struts的基本概念&#xff0c;怎样搭建struts开发环境&#xff0c;从编写formbean&#xff0c;action到jsp页面&#xff0c;以及怎样将他…

用 Python 脚本实现电脑唤醒后自动拍照 截屏并发邮件通知

背景 背景是这样的, 我的家里台式机常年 休眠, 并配置了 Wake On Lan (WOL) 方便远程唤醒并使用。 但是我发现, 偶尔台式机会被其他情况唤醒, 这时候我并不知道, 结果白白运行了好几天, 浪费了很多电。 所以我的需求是这样的&#xff1a; &#x1f914; 电脑唤醒后(可能是开…