【Linux详解】——共享内存
📖 前言:本期介绍共享内存。
目录
- 🕒 1. 共享内存的原理
- 🕒 2. 共享内存的概念
- 🕘 2.1 接口认识
- 🕘 2.2 演示生成key的唯一性
- 🕘 2.3 再谈key
- 🕒 3. 共享内存相关命令
- 🕒 4. 利用共享内存进行进程间通信
- 🕒 5. 共享内存的优缺点
🕒 1. 共享内存的原理
在之前学过的进程地址空间的基础上,我们知道,进程之间具有独立性,因为每个进程的内核数据结构的数据以及页表的映射都是独立的。而对于共享内存,我们同样了解,这是为了让进程之间能够进行通信的公共空间,接下来就通过进程地址空间的结构去了解共享空间的位置及原理:
OS为了让两个毫不相关的进程之间进行通信,进行了三个工作:
- 在对应的内存当中让用户帮OS申请一块空间(通过指定的调用接口)
- 将创建好的内存映射进进程的地址空间(用户就可以通过访问起始地址的方式来进行对申请的这块内存空间的访问)
- 未来不想通信:
- 取消进程和内存的映射关系
- 释放内存
因此,我们把申请的这块空间称之为共享内存,将映射关系称之为进程和共享内存进行挂接。将取消进程和内存的映射关系称之为去关联,释放内存释放的就是共享内存。
理解:
- 进程间通信,是专门设计的,用来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值,则通过一个新的接口:ftok
,ftok
通过指定的字符串数据*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详解】——共享内存
📖 前言:本期介绍共享内存。 目录 🕒 1. 共享内存的原理🕒 2. 共享内存的概念🕘 2.1 接口认识🕘 2.2 演示生成key的唯一性🕘 2.3 再谈key 🕒 3. 共享内存相关命令🕒 4. 利…...
Golang 几个不错的实用函数库
文章目录 samber/lothoas/go-funkduke-git/lancetelliotchance/piegookit/goutildablelv/cyan 大咖好呀,我是恋喵大鲤鱼。 Golang 标准库是 Go 语言自带的一组核心功能库,功能全面,易于使用。 在 Golang 标准库的基础上,还可以进…...

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

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

JavaScript基础06——let和var两个关键字有啥不同
哈喽,小伙伴们大家好,我是雷工! 每日学习一点点,今天继续学习JavaScript基础知识,下面是学习笔记。 1、变量的本质 内存:计算机中存储数据的地方,相当于一空间。 变量的本质:是程序…...
Apache Doris 2.0.1 1.2.7 版本正式发布!
亲爱的社区小伙伴们,我们很高兴的宣布,2023 年 9 月 4 日 我们正式发布了 Apache Doris 2.0.1 和 Apache Doris 1.2.7 这两个版本,这两个版本由上百名位贡献者共同努力完成的,提供了更多有用的新特性,同时修复了若干已…...

YOLOv5算法改进(11)— 替换主干网络之EfficientNetv2
前言:Hello大家好,我是小哥谈。EfficientNetV2是一个网络模型,旨在提供更小的模型和更快的训练速度。它是EfficientNetV1的改进版本。EfficientNetV2通过使用更小的模型参数和采用一种称为Progressive Learning的渐进学习策略来实现这一目标。…...
Lombok讲解
Lombok是一个可以通过简单的注解形式来帮助我们简化消除一些必须有但显得很臃肿的Java代码的工具,如:getter、setter、equals、hashCode、toString等。 Lombok的常用注解有: Data:这是一个自定义注解,它相当于Getter…...
【Android】功能丰富的dumpsys activity
在Android中,要查看客户端Binder的连接数,可以通过dumpsys命令结合service参数来获取相关信息。请按照以下步骤进行操作: 连接到设备的计算机上,打开命令行终端。 使用adb shell命令进入设备的Shell环境。 执行以下命令来查看服…...

亚马逊云科技 云技能孵化营——我的云技能之旅
文章目录 每日一句正能量前言活动流程后记 每日一句正能量 不能在已经获得足够多的成功时,还对自己的能力保持怀疑,露出自信的微笑,走出自信的步伐,做一个自信的人! 前言 亚马逊云科技 (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 一、环境信…...
汽车信息安全导图
尊敬的读者们,欢迎来到我的信息安全专栏。在这个专栏中,我将结合我在信息安全领域的开发经验,为大家深入浅出地讲解信息安全的重要性和相关知识点。 在数字化时代,信息成为了我们生活中不可或缺的一部分。我们的个人信息、交易数据、社交网络、公司机密等都以电子形式存储…...
【元宇宙】区块链,元宇宙最大化的驱动力
如今,一些观察者认为区块链是在结构上实现元宇宙的必要条件,而其他人则认为这种说法是荒谬的。人们对于区块链技术本身仍然有很多困惑,所以根本谈不上清楚地了解込块链技术与元宇宙的关系。所以,我们可以从区块链的定义开始介绍。…...

$ref属性的介绍与使用
在Vue.js中,$ref是一个特殊的属性,用于访问Vue组件中的DOM元素或子组件实例。它允许你直接访问组件内部的DOM元素或子组件,并且可以在需要时进行操作或修改。以下是有关$ref的详细介绍和示例演示,给大家做一个简单的介绍和概念区分…...
Holistic Evaluation of Language Models
本文是LLM系列文章,针对《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 这是一种默认的属性,在不进行明确指定的情况下,系…...

北京已收录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的正则表达式
概述 在上一节,我们介绍了Python的文件操作,包括:打开文件、读取文件、写入文件、关闭文件、文件指针移动、获取目录列表等内容。在这一节中,我们将介绍Python的正则表达式。正则表达式是一种强大的工具,用于在文本中进…...

关于工信部发布的app备案以及小程序备案流程
一、相关政策 通知:https://beian.miit.gov.cn/#/Integrated/lawStatute 腾讯备案:网站备案 首次备案-网站备案-文档中心-腾讯云 阿里备案:网站备案_ICP备案_备案迁移_备案-阿里云 二、遇到的问题 APP备案 安卓获取平台公钥方法…...
生成xcframework
打包 XCFramework 的方法 XCFramework 是苹果推出的一种多平台二进制分发格式,可以包含多个架构和平台的代码。打包 XCFramework 通常用于分发库或框架。 使用 Xcode 命令行工具打包 通过 xcodebuild 命令可以打包 XCFramework。确保项目已经配置好需要支持的平台…...

React第五十七节 Router中RouterProvider使用详解及注意事项
前言 在 React Router v6.4 中,RouterProvider 是一个核心组件,用于提供基于数据路由(data routers)的新型路由方案。 它替代了传统的 <BrowserRouter>,支持更强大的数据加载和操作功能(如 loader 和…...
Java毕业设计:WML信息查询与后端信息发布系统开发
JAVAWML信息查询与后端信息发布系统实现 一、系统概述 本系统基于Java和WML(无线标记语言)技术开发,实现了移动设备上的信息查询与后端信息发布功能。系统采用B/S架构,服务器端使用Java Servlet处理请求,数据库采用MySQL存储信息࿰…...

【笔记】WSL 中 Rust 安装与测试完整记录
#工作记录 WSL 中 Rust 安装与测试完整记录 1. 运行环境 系统:Ubuntu 24.04 LTS (WSL2)架构:x86_64 (GNU/Linux)Rust 版本:rustc 1.87.0 (2025-05-09)Cargo 版本:cargo 1.87.0 (2025-05-06) 2. 安装 Rust 2.1 使用 Rust 官方安…...

Kafka入门-生产者
生产者 生产者发送流程: 延迟时间为0ms时,也就意味着每当有数据就会直接发送 异步发送API 异步发送和同步发送的不同在于:异步发送不需要等待结果,同步发送必须等待结果才能进行下一步发送。 普通异步发送 首先导入所需的k…...

认识CMake并使用CMake构建自己的第一个项目
1.CMake的作用和优势 跨平台支持:CMake支持多种操作系统和编译器,使用同一份构建配置可以在不同的环境中使用 简化配置:通过CMakeLists.txt文件,用户可以定义项目结构、依赖项、编译选项等,无需手动编写复杂的构建脚本…...
ubuntu22.04 安装docker 和docker-compose
首先你要确保没有docker环境或者使用命令删掉docker sudo apt-get remove docker docker-engine docker.io containerd runc安装docker 更新软件环境 sudo apt update sudo apt upgrade下载docker依赖和GPG 密钥 # 依赖 apt-get install ca-certificates curl gnupg lsb-rel…...

归并排序:分治思想的高效排序
目录 基本原理 流程图解 实现方法 递归实现 非递归实现 演示过程 时间复杂度 基本原理 归并排序(Merge Sort)是一种基于分治思想的排序算法,由约翰冯诺伊曼在1945年提出。其核心思想包括: 分割(Divide):将待排序数组递归地分成两个子…...

RushDB开源程序 是现代应用程序和 AI 的即时数据库。建立在 Neo4j 之上
一、软件介绍 文末提供程序和源码下载 RushDB 改变了您处理图形数据的方式 — 不需要 Schema,不需要复杂的查询,只需推送数据即可。 二、Key Features ✨ 主要特点 Instant Setup: Be productive in seconds, not days 即时设置 :在几秒钟…...

初探用uniapp写微信小程序遇到的问题及解决(vue3+ts)
零、关于开发思路 (一)拿到工作任务,先理清楚需求 1.逻辑部分 不放过原型里说的每一句话,有疑惑的部分该问产品/测试/之前的开发就问 2.页面部分(含国际化) 整体看过需要开发页面的原型后,分类一下哪些组件/样式可以复用,直接提取出来使用 (时间充分的前提下,不…...