当前位置: 首页 > news >正文

【Linux详解】——共享内存

📖 前言:本期介绍共享内存。


目录

  • 🕒 1. 共享内存的原理
  • 🕒 2. 共享内存的概念
    • 🕘 2.1 接口认识
    • 🕘 2.2 演示生成key的唯一性
    • 🕘 2.3 再谈key
  • 🕒 3. 共享内存相关命令
  • 🕒 4. 利用共享内存进行进程间通信
  • 🕒 5. 共享内存的优缺点

🕒 1. 共享内存的原理

在之前学过的进程地址空间的基础上,我们知道,进程之间具有独立性,因为每个进程的内核数据结构的数据以及页表的映射都是独立的。而对于共享内存,我们同样了解,这是为了让进程之间能够进行通信的公共空间,接下来就通过进程地址空间的结构去了解共享空间的位置及原理:
在这里插入图片描述

OS为了让两个毫不相关的进程之间进行通信,进行了三个工作:

  1. 在对应的内存当中让用户帮OS申请一块空间(通过指定的调用接口)
  2. 将创建好的内存映射进进程的地址空间(用户就可以通过访问起始地址的方式来进行对申请的这块内存空间的访问)
  3. 未来不想通信:
    • 取消进程和内存的映射关系
    • 释放内存

因此,我们把申请的这块空间称之为共享内存,将映射关系称之为进程和共享内存进行挂接。将取消进程和内存的映射关系称之为去关联,释放内存释放的就是共享内存。

理解

  • 进程间通信,是专门设计的,用来IPC的,和malloc/new不是一个东西。
  • 共享内存是一种通信方式,所有想通信的进程,都可以用。
  • OS中一定会存在着很多共享内存。

🕒 2. 共享内存的概念

通过让不同的进程,看到同一个内存块的方式,叫做共享内存。

🕘 2.1 接口认识

#include<sys/ipc.h>
#include<sys/shm.h>int shmget(key_t key, size_t size, int shmflg);// size:共享内存的大小

对于shmflg,常见的有两种选择:

  • IPC_CREAT:如果不存在共享文件则创建,存在则获取
  • IPC_EXCL
    • 无法单独使用,单独使用没有意义,需要结合IPC_CREAT
    • IPC_CREAT|IPC_EXCL:如果不存在,就创建,如果已存在,就出错返回。即在用户的角度,如果创建成功,一定是一个新的shm

shmget返回值: 记住他是一个标识符就够用了,得到的是共享内存的标识符。(和文件fd没有任何关系)

key: 是什么不重要,最重要的是其具备的唯一性。

而获取key值,则通过一个新的接口:ftokftok通过指定的字符串数据*pathname以及char类型的proj_id数据进行一系列的算法整合返回了具有唯一性的Key:

key_t ftok(char *pathname, char proj_id);

由于创建的key值有可能已经被别人使用了,因此有失败的可能性。创建Key值如果失败,则返回-1。

🕘 2.2 演示生成key的唯一性

# Makefile
.PHONY:all
all:shm_client shm_servershm_client:shm_client.ccg++ -o $@ $^ -std=c++11
shm_server:shm_server.ccg++ -o $@ $^ -std=c++11.PHONY:clean
clean:rm -f shm_client shm_server
// comm.hpp
#ifndef _COMM_HPP_
#define _COMM_HPP_#include<iostream>
#include<cerrno>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<sys/ipc.h>
#include<sys/shm.h>#define PATHNAME "."//当前路径
#define PROJ_ID 0x66key_t getKey()
{key_t k = ftok(PATHNAME, PROJ_ID);if(k < 0){// cin, cout, cerr ->stdin, stdout, stderr->0, 1, 2;标准错误stderr向2打印。std::cerr << errno << ":" << strerror(errno) << std::endl;exit(1);//终止进程}return k;
}#endif
// shm_server.cc
#include"comm.hpp"int main()
{key_t k = getKey();printf("0x%x\n", k);return 0;
}
// shm_client.cc
#include"comm.hpp"int main()
{key_t k = getKey();printf("0x%x\n", k);return 0;
}
[hins@VM-12-13-centos shm]$ ./shm_server
0x6601062a
[hins@VM-12-13-centos shm]$ ./shm_client
0x6601062a

通过make后执行发现,两个程序的k值是一样的,这就证明了ftok指定参数的返回值是唯一的。(k实际上就是32位的一个整数)

🕘 2.3 再谈key

OS中一定存在多个共享内存,因为彼此之间可能都需要通信,因此也就都需要申请一块空间。而OS申请的共享空间,也一定和进程一样需要被管理,既然需要管理,那么一定也是先描述再组织的方式,即共享内存 = 物理内存块+共享内存的相关属性 。

之前谈到过,key是什么不重要,能进行唯一性的标识最重要,因此创建共享内存的时候,是如何保证共享内存在系统中是唯一的呢?当然是通过key来确定的,只要一个进程也看到了同一个key,就能够访问这个共享内存。那么key在哪里,实际上这就和PCB一样,key就在内核中的属性集合里,即:

struct shm{key_t key;//...
}

即:key是通过shmget这样的系统调用,设置进入共享内存属性中,用来表示该共享内存在内核中的唯一性!

shmid和key就好比fd和inode。为什么有了key还需要shmid呢?通过key和shmid的区分,能够面向系统层面和用户层面,这样能够更好的进行解耦,以免内核中的变化影响到用户级。

🕒 3. 共享内存相关命令

通过让不同的进程,看到同一个内存块的方式,叫做共享内存。

查看共享内存ipcs -m/-q/-s (共享内存/消息队列/信号量数组)

删除共享内存ipcrm -m shmnid

将共享内存与虚拟内存进行关联:

#include <sys/types.h>
#include <sys/shm.h>
void *shmat(int shmid, const void *shmaddr, int shmflg);// 共享内存id,被映射的进程地址空间(给nullptr),给0默认可以读写。成功时,将返回共享内存的虚拟地址。失败返回-1(失败错误码errno被设置) 

将共享内存与虚拟内存去关联

#include <sys/types.h>
#include <sys/shm.h>
int shmdt(const void *shmaddr);//参数:shmat的返回值。成功时,将返回0。失败返回-1(失败错误码errno被设置)

控制(主要用移除)共享内存(shmctl)

#include <sys/ipc.h>
#include <sys/shm.h>
int shmctl(int shmid, int cmd, struct shmid_ds *buf);//shmid(类似fd),传入系统设定的宏,shmid_ds数据结构。传入IPC_RMID移除共享内存成功时,将返回0。失败返回-1(失败错误码errno被设置)

🕒 4. 利用共享内存进行进程间通信

// comm.hpp
#pragma once
#include <iostream>
#include <cerrno>
#include <cstring>
#include <cstdlib>
#include <cstdlib>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>#define PATHNAME "."//当前路径(路径都行)
#define PROJ_ID 0X55//项目id也无要求
#define MAX_SIZE 4096
key_t getKey()
{key_t k=ftok(PATHNAME, PROJ_ID);if(k==-1){std::cout<<"ftok"<<errno<<":"<<strerror(errno)<<std::endl;exit(1);}return k;
}
int getShmHelper(key_t key,int flags)
{int shmid=shmget(key,MAX_SIZE,flags);if(shmid==-1)//创建共享内存失败{std::cerr<<"shmget"<<errno<<":"<<strerror(errno)<<std::endl;exit(2);}return shmid;//返回共享内存标识符
}
int getShm(key_t key)//创建||获取共享内存
{return getShmHelper(key,IPC_CREAT);//传0也行
}
int createShm(key_t key)//必定创建共享内存
{return getShmHelper(key,IPC_CREAT|IPC_EXCL|0600);//生成一个全新的共享内存
}
void* attachShm(int shmid)//让共享内存与虚拟内存建立联系
{void* memstart=shmat(shmid,nullptr,0);if((long long)memstart==-1L){std::cerr<<"shmat"<<errno<<":"<<strerror<<std::endl;exit(3);}return memstart;
} 
void detchShm(void* memStart)//去关联
{if(shmdt(memStart)==-1){std::cerr<<"shmdt"<<errno<<":"<<strerror<<std::endl;exit(4);}
}   
void delShm(int shmid)//删除共享内存
{if(shmctl(shmid,IPC_RMID,nullptr)==-1){std::cerr<<"shmctl"<<errno<<":"<<strerror<<std::endl;}
}
// shm_server.cc
#include "comm.hpp"
int main()
{key_t k=getKey();printf("0X%x\n",k);int shmid=createShm(k);char* memStart=(char*)attachShm(shmid);//让共享内存与虚拟内存建立联系printf("memStart address:%p\n",memStart); //通信接收代码while(true){printf("client say:%s\n",memStart); sleep(1);//调用用户级结构体struct shmid_ds ds;//创建结构体对象dsshmctl(shmid,IPC_STAT,&ds);//获取ds对象的状态printf("获取属性:%d,pid:%d,myself:%d,key:%d\n",ds.shm_segsz,getpid(),ds.shm_cpid,ds.shm_perm.__key);}detchShm(memStart);//去关联sleep(10);delShm(shmid);//删除共享内存,client和server都能删除共享内存,尽量谁创建谁删return 0;
}
// shm_client.cc
#include "comm.hpp"
int main()
{key_t k=getKey();printf("0X%x\n",k);int shmid=getShm(k);//获取共享内存sleep(5);char* memStart=(char*)attachShm(shmid);//让共享内存与虚拟内存建立联系printf("memStart address:%p\n",memStart); //通信传输代码const char* massage="I am client";pid_t id=getpid();int cnt=0;//发送计数while(true){snprintf(memStart,MAX_SIZE,"%s[%d]:%d\n",massage,getpid,++cnt);sleep(1);}detchShm(memStart);//去关联return 0;
}

🕒 5. 共享内存的优缺点

优点:共享内存是所有进程间通信中速度最快的。(无需缓冲区,能大大减少通信数据的拷贝次数)

缺点:如果服务端读取速度较快,用户端发送数据较慢,就会产生同一段消息被服务端读取多遍。共享内存是不进行同步和互斥的,没有对数据进行任何保护。

共享内存大小的建议:因为系统分配共享内存是以4KB为基本单位,一般建议申请共享内存的大小为4KB的整数倍。


OK,以上就是本期知识点“共享内存”的知识啦~~ ,感谢友友们的阅读。后续还会继续更新,欢迎持续关注哟📌~
💫如果有错误❌,欢迎批评指正呀👀~让我们一起相互进步🚀
🎉如果觉得收获满满,可以点点赞👍支持一下哟~

❗ 转载请注明出处
作者:HinsCoder
博客链接:🔎 作者博客主页

相关文章:

【Linux详解】——共享内存

&#x1f4d6; 前言&#xff1a;本期介绍共享内存。 目录 &#x1f552; 1. 共享内存的原理&#x1f552; 2. 共享内存的概念&#x1f558; 2.1 接口认识&#x1f558; 2.2 演示生成key的唯一性&#x1f558; 2.3 再谈key &#x1f552; 3. 共享内存相关命令&#x1f552; 4. 利…...

Golang 几个不错的实用函数库

文章目录 samber/lothoas/go-funkduke-git/lancetelliotchance/piegookit/goutildablelv/cyan 大咖好呀&#xff0c;我是恋喵大鲤鱼。 Golang 标准库是 Go 语言自带的一组核心功能库&#xff0c;功能全面&#xff0c;易于使用。 在 Golang 标准库的基础上&#xff0c;还可以进…...

【Linux】地址空间概念

目录 前言&#xff1a; 地址空间回顾 验证&#xff1a;一个变量是否会有两个值&#xff1f; 一. 什么是地址空间 虚拟地址与物理地址之间的关系 二. 地址空间是如何设计的 1. 回答一个变量两个值 2.扩展 继续深入理解 三. 为什么要有地址空间 原因&#xff1a; 1. 使…...

视频集中存储/直播点播平台EasyDSS点播文件分类功能新升级

视频推拉流EasyDSS视频直播点播平台&#xff0c;集视频直播、点播、转码、管理、录像、检索、时移回看等功能于一体&#xff0c;可提供音视频采集、视频推拉流、播放H.265编码视频、存储、分发等视频能力服务。 TSINGSEE青犀视频的EasyDSS平台具有点播文件分类展示方法&#xf…...

JavaScript基础06——let和var两个关键字有啥不同

哈喽&#xff0c;小伙伴们大家好&#xff0c;我是雷工&#xff01; 每日学习一点点&#xff0c;今天继续学习JavaScript基础知识&#xff0c;下面是学习笔记。 1、变量的本质 内存&#xff1a;计算机中存储数据的地方&#xff0c;相当于一空间。 变量的本质&#xff1a;是程序…...

Apache Doris 2.0.1 1.2.7 版本正式发布!

亲爱的社区小伙伴们&#xff0c;我们很高兴的宣布&#xff0c;2023 年 9 月 4 日 我们正式发布了 Apache Doris 2.0.1 和 Apache Doris 1.2.7 这两个版本&#xff0c;这两个版本由上百名位贡献者共同努力完成的&#xff0c;提供了更多有用的新特性&#xff0c;同时修复了若干已…...

YOLOv5算法改进(11)— 替换主干网络之EfficientNetv2

前言&#xff1a;Hello大家好&#xff0c;我是小哥谈。EfficientNetV2是一个网络模型&#xff0c;旨在提供更小的模型和更快的训练速度。它是EfficientNetV1的改进版本。EfficientNetV2通过使用更小的模型参数和采用一种称为Progressive Learning的渐进学习策略来实现这一目标。…...

Lombok讲解

Lombok是一个可以通过简单的注解形式来帮助我们简化消除一些必须有但显得很臃肿的Java代码的工具&#xff0c;如&#xff1a;getter、setter、equals、hashCode、toString等。 Lombok的常用注解有&#xff1a; Data&#xff1a;这是一个自定义注解&#xff0c;它相当于Getter…...

【Android】功能丰富的dumpsys activity

在Android中&#xff0c;要查看客户端Binder的连接数&#xff0c;可以通过dumpsys命令结合service参数来获取相关信息。请按照以下步骤进行操作&#xff1a; 连接到设备的计算机上&#xff0c;打开命令行终端。 使用adb shell命令进入设备的Shell环境。 执行以下命令来查看服…...

亚马逊云科技 云技能孵化营——我的云技能之旅

文章目录 每日一句正能量前言活动流程后记 每日一句正能量 不能在已经获得足够多的成功时&#xff0c;还对自己的能力保持怀疑&#xff0c;露出自信的微笑&#xff0c;走出自信的步伐&#xff0c;做一个自信的人&#xff01; 前言 亚马逊云科技 (Amazon Web Services) 是全球云…...

南大通用数据库-Gbase-8a-学习-38-常规日志(general log)

目录 一、环境信息 二、general log的用途 三、general log相关参数介绍 四、LInux环境模拟实验 1、查看参数配置 2、开启general log 3、输入测试SQL 4、查看文件级别general log 5、改为表级别general log 6、再次输入测试SQL 7、查看gbase.general_log 一、环境信…...

汽车信息安全导图

尊敬的读者们,欢迎来到我的信息安全专栏。在这个专栏中,我将结合我在信息安全领域的开发经验,为大家深入浅出地讲解信息安全的重要性和相关知识点。 在数字化时代,信息成为了我们生活中不可或缺的一部分。我们的个人信息、交易数据、社交网络、公司机密等都以电子形式存储…...

【元宇宙】区块链,元宇宙最大化的驱动力

如今&#xff0c;一些观察者认为区块链是在结构上实现元宇宙的必要条件&#xff0c;而其他人则认为这种说法是荒谬的。人们对于区块链技术本身仍然有很多困惑&#xff0c;所以根本谈不上清楚地了解込块链技术与元宇宙的关系。所以&#xff0c;我们可以从区块链的定义开始介绍。…...

$ref属性的介绍与使用

在Vue.js中&#xff0c;$ref是一个特殊的属性&#xff0c;用于访问Vue组件中的DOM元素或子组件实例。它允许你直接访问组件内部的DOM元素或子组件&#xff0c;并且可以在需要时进行操作或修改。以下是有关$ref的详细介绍和示例演示&#xff0c;给大家做一个简单的介绍和概念区分…...

Holistic Evaluation of Language Models

本文是LLM系列文章&#xff0c;针对《Holistic Evaluation of Language Models》的翻译。 语言模型的整体评价 摘要1 引言2 前言3 核心场景4 一般指标5 有针对性的评估6 模型7 通过提示进行调整8 实验和结果9 相关工作和讨论10 缺失11 不足和未来工作12 结论 摘要 语言模型&a…...

android 布局 横屏 android横屏适配

一、刘海屏适配 1、layoutInDisplayCutoutMode属性 Android 9.0系统中提供了3种layoutInDisplayCutoutMode属性来允许应用自主决定该如何对刘海屏设备进行适配。 LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT 这是一种默认的属性&#xff0c;在不进行明确指定的情况下&#xff0c;系…...

北京已收录2023开学了《乡村振兴战略下传统村落文化旅游设计》中国建筑出版传媒许少辉八一新书

北京已收录2023开学了《乡村振兴战略下传统村落文化旅游设计》中国建筑出版传媒许少辉八一新书...

【Linux】Ubuntu20.04版本配置pytorch环境2023.09.05【教程】

【Linux】Ubuntu20.04版本配置pytorch环境2023.09.05【教程】 文章目录 【Linux】Ubuntu20.04版本配置pytorch环境2023.09.05【教程】一、安装Anaconda虚拟环境管理器二、创建虚拟环境并激活三、安装Pytorch四、测试pytorchReference 一、安装Anaconda虚拟环境管理器 首先进入…...

11 Python的正则表达式

概述 在上一节&#xff0c;我们介绍了Python的文件操作&#xff0c;包括&#xff1a;打开文件、读取文件、写入文件、关闭文件、文件指针移动、获取目录列表等内容。在这一节中&#xff0c;我们将介绍Python的正则表达式。正则表达式是一种强大的工具&#xff0c;用于在文本中进…...

关于工信部发布的app备案以及小程序备案流程

一、相关政策 通知&#xff1a;https://beian.miit.gov.cn/#/Integrated/lawStatute 腾讯备案&#xff1a;网站备案 首次备案-网站备案-文档中心-腾讯云 阿里备案&#xff1a;网站备案_ICP备案_备案迁移_备案-阿里云 二、遇到的问题 APP备案 安卓获取平台公钥方法&#xf…...

RocketMQ延迟消息机制

两种延迟消息 RocketMQ中提供了两种延迟消息机制 指定固定的延迟级别 通过在Message中设定一个MessageDelayLevel参数&#xff0c;对应18个预设的延迟级别指定时间点的延迟级别 通过在Message中设定一个DeliverTimeMS指定一个Long类型表示的具体时间点。到了时间点后&#xf…...

脑机新手指南(八):OpenBCI_GUI:从环境搭建到数据可视化(下)

一、数据处理与分析实战 &#xff08;一&#xff09;实时滤波与参数调整 基础滤波操作 60Hz 工频滤波&#xff1a;勾选界面右侧 “60Hz” 复选框&#xff0c;可有效抑制电网干扰&#xff08;适用于北美地区&#xff0c;欧洲用户可调整为 50Hz&#xff09;。 平滑处理&…...

PHP和Node.js哪个更爽?

先说结论&#xff0c;rust完胜。 php&#xff1a;laravel&#xff0c;swoole&#xff0c;webman&#xff0c;最开始在苏宁的时候写了几年php&#xff0c;当时觉得php真的是世界上最好的语言&#xff0c;因为当初活在舒适圈里&#xff0c;不愿意跳出来&#xff0c;就好比当初活在…...

MySQL 隔离级别:脏读、幻读及不可重复读的原理与示例

一、MySQL 隔离级别 MySQL 提供了四种隔离级别,用于控制事务之间的并发访问以及数据的可见性,不同隔离级别对脏读、幻读、不可重复读这几种并发数据问题有着不同的处理方式,具体如下: 隔离级别脏读不可重复读幻读性能特点及锁机制读未提交(READ UNCOMMITTED)允许出现允许…...

ETLCloud可能遇到的问题有哪些?常见坑位解析

数据集成平台ETLCloud&#xff0c;主要用于支持数据的抽取&#xff08;Extract&#xff09;、转换&#xff08;Transform&#xff09;和加载&#xff08;Load&#xff09;过程。提供了一个简洁直观的界面&#xff0c;以便用户可以在不同的数据源之间轻松地进行数据迁移和转换。…...

Module Federation 和 Native Federation 的比较

前言 Module Federation 是 Webpack 5 引入的微前端架构方案&#xff0c;允许不同独立构建的应用在运行时动态共享模块。 Native Federation 是 Angular 官方基于 Module Federation 理念实现的专为 Angular 优化的微前端方案。 概念解析 Module Federation (模块联邦) Modul…...

Spring AI 入门:Java 开发者的生成式 AI 实践之路

一、Spring AI 简介 在人工智能技术快速迭代的今天&#xff0c;Spring AI 作为 Spring 生态系统的新生力量&#xff0c;正在成为 Java 开发者拥抱生成式 AI 的最佳选择。该框架通过模块化设计实现了与主流 AI 服务&#xff08;如 OpenAI、Anthropic&#xff09;的无缝对接&…...

自然语言处理——Transformer

自然语言处理——Transformer 自注意力机制多头注意力机制Transformer 虽然循环神经网络可以对具有序列特性的数据非常有效&#xff0c;它能挖掘数据中的时序信息以及语义信息&#xff0c;但是它有一个很大的缺陷——很难并行化。 我们可以考虑用CNN来替代RNN&#xff0c;但是…...

SpringCloudGateway 自定义局部过滤器

场景&#xff1a; 将所有请求转化为同一路径请求&#xff08;方便穿网配置&#xff09;在请求头内标识原来路径&#xff0c;然后在将请求分发给不同服务 AllToOneGatewayFilterFactory import lombok.Getter; import lombok.Setter; import lombok.extern.slf4j.Slf4j; impor…...

【Android】Android 开发 ADB 常用指令

查看当前连接的设备 adb devices 连接设备 adb connect 设备IP 断开已连接的设备 adb disconnect 设备IP 安装应用 adb install 安装包的路径 卸载应用 adb uninstall 应用包名 查看已安装的应用包名 adb shell pm list packages 查看已安装的第三方应用包名 adb shell pm list…...