当前位置: 首页 > 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…...

日语AI面试高效通关秘籍:专业解读与青柚面试智能助攻

在如今就业市场竞争日益激烈的背景下&#xff0c;越来越多的求职者将目光投向了日本及中日双语岗位。但是&#xff0c;一场日语面试往往让许多人感到步履维艰。你是否也曾因为面试官抛出的“刁钻问题”而心生畏惧&#xff1f;面对生疏的日语交流环境&#xff0c;即便提前恶补了…...

【JavaEE】-- HTTP

1. HTTP是什么&#xff1f; HTTP&#xff08;全称为"超文本传输协议"&#xff09;是一种应用非常广泛的应用层协议&#xff0c;HTTP是基于TCP协议的一种应用层协议。 应用层协议&#xff1a;是计算机网络协议栈中最高层的协议&#xff0c;它定义了运行在不同主机上…...

[Java恶补day16] 238.除自身以外数组的乘积

给你一个整数数组 nums&#xff0c;返回 数组 answer &#xff0c;其中 answer[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积 。 题目数据 保证 数组 nums之中任意元素的全部前缀元素和后缀的乘积都在 32 位 整数范围内。 请 不要使用除法&#xff0c;且在 O(n) 时间复杂度…...

Linux 内存管理实战精讲:核心原理与面试常考点全解析

Linux 内存管理实战精讲&#xff1a;核心原理与面试常考点全解析 Linux 内核内存管理是系统设计中最复杂但也最核心的模块之一。它不仅支撑着虚拟内存机制、物理内存分配、进程隔离与资源复用&#xff0c;还直接决定系统运行的性能与稳定性。无论你是嵌入式开发者、内核调试工…...

MySQL:分区的基本使用

目录 一、什么是分区二、有什么作用三、分类四、创建分区五、删除分区 一、什么是分区 MySQL 分区&#xff08;Partitioning&#xff09;是一种将单张表的数据逻辑上拆分成多个物理部分的技术。这些物理部分&#xff08;分区&#xff09;可以独立存储、管理和优化&#xff0c;…...

关于easyexcel动态下拉选问题处理

前些日子突然碰到一个问题&#xff0c;说是客户的导入文件模版想支持部分导入内容的下拉选&#xff0c;于是我就找了easyexcel官网寻找解决方案&#xff0c;并没有找到合适的方案&#xff0c;没办法只能自己动手并分享出来&#xff0c;针对Java生成Excel下拉菜单时因选项过多导…...

ui框架-文件列表展示

ui框架-文件列表展示 介绍 UI框架的文件列表展示组件&#xff0c;可以展示文件夹&#xff0c;支持列表展示和图标展示模式。组件提供了丰富的功能和可配置选项&#xff0c;适用于文件管理、文件上传等场景。 功能特性 支持列表模式和网格模式的切换展示支持文件和文件夹的层…...

【实施指南】Android客户端HTTPS双向认证实施指南

&#x1f510; 一、所需准备材料 证书文件&#xff08;6类核心文件&#xff09; 类型 格式 作用 Android端要求 CA根证书 .crt/.pem 验证服务器/客户端证书合法性 需预置到Android信任库 服务器证书 .crt 服务器身份证明 客户端需持有以验证服务器 客户端证书 .crt 客户端身份…...

以太网PHY布局布线指南

1. 简介 对于以太网布局布线遵循以下准则很重要&#xff0c;因为这将有助于减少信号发射&#xff0c;最大程度地减少噪声&#xff0c;确保器件作用&#xff0c;最大程度地减少泄漏并提高信号质量。 2. PHY设计准则 2.1 DRC错误检查 首先检查DRC规则是否设置正确&#xff0c;然…...

【汇编逆向系列】四、函数调用包含单个参数之Double类型-mmword,movsd,mulsd,addsd指令,总结汇编的数据类型

一、汇编代码 上一节开始&#xff0c;讲到了很多debug编译独有的汇编方式&#xff0c;为了更好的区分release的编译器优化和debug的区别&#xff0c;从本章节开始将会提供debug和release的汇编用作对比 Debugb编译 single_double_param:00000000000000A0: F2 0F 11 44 24 08…...