Linux共享内存(System V)

news2025/1/18 7:27:42

前言:在前面章节,我们学习了2种进程间通信方式,一个是通过继承方式的匿名管道,一个是通过让有血缘关系的进程在内存中看到同一份文件进行通信。此外,还可以在内存中开辟一块物理内存,通过页表映射到进程的进程地址空间中的共享内存段,也能进行进程间通信。

1:共享内存示意图

2:共享内存原理

原理: 在内存中开辟物理空间的共享内存,通过计算机的页表映射,映射到需要通信进程的进程地址空间中,操作系统再将该进程地址空间的虚拟地址反馈给客户端,客户端就可以拿到该共享内存的起始地址。对这块地址的操作就可以实现进程间的通信。

因此,使用共享内存通信分为三个步骤:

  1. 创建
  2. 关联进程和取消关联
  3. 释放共享内存

下面做出几个思考:

  1. 系统使用shm通信,是不是只有一对进程会使用共享内存呢? 答案:可能会有多个进程使用共享内存,因此会有多个共享内存被用来通信!
  2.  系统中一定会存在多个共享内存,操作系统要不要管理所有的共享内存呢? 答案:要!
  3. 如何管理多个共享内存呢? 答案:先描述,再组织。
  4. 对共享内存的管理就是对共享内存内核数据结构的管理(伪代码:struct shm),构建描述共享内存的结构体对象,和进程pcb一样!
  5. 进程间通信的前提是,让进程看到同一份资源!如何做到?

 3:系统接口

 这是创建共享内存的接口。

 第一个参数我们还不知道,后面讲,

第二个参数是开辟的共享内存大小

 

第三个参数类似文件系统里面的O_CREAT,O_APPEND,O_EXCL,O_TRUNC,这里的 IPC_CREAT就是表示如果没有共享内存就创建,如果有就获取共享内存并且返回。

如果加上IPC_EXCL则表示如果没有共享内存就创建,如果有就报错返回。

 函数的返回值是共享内存的id,为int类型。失败则返回-1。

3.1:key的含义

因为系统中可能会存在多个共享内存,如果AB进程需要通信,申请了一块共享内存,如何让两个进程都找到这块共享内存呢?这就体现了key的作用。

假设A进程是server,B进程是client,当A进程通过某个函数生成了一个key值,在申请共享内存的时候,他将key放到这个共享内存的描述结构体中,只要B进程通过某个函数,并且传参和A一样,也可以获取到一个一样的key,那么B进程拿着自己的key去与每一个共享内存结构体中的key匹配,如果匹配成功,那么B就可以和A看到同一份共享内存了,至此进程间通信的前提也就达到了。

3.2:key的获取方法

 第一个参数是路径字符串,第二个参数是项目ID(可以随便设置比如0X6666);

key的本质是在内核中使用的。

因此当服务端使用shmget,是将key插入shm描述结构体中,客户端使用shmget是用key去匹配。

 4:共享内存使用实例

4.1:makefile

.PHONY:all
all:server client

server:server.cc
	g++ -o $@ $^ -std=c++11
client:client.cc
	g++ -o $@ $^ -std=c++11

.PHONY:clean
clean:
	rm -rf server client

4.2:comm.cpp

因为客户端和服务端都需要使用shmget接口,甚至于后面还要与共享内存挂上联系,那不如直接使用一份公共文件。

4.2.1:创建共享内存与匹配共享内存接口:creatShmHelper

int createShmHelper(key_t k,int size,int flag)
{
    int shmid = shmget(k,gsize,flag);
    if(shmid==-1)exit(2);
    return shmid;

}
int createShm(key_t k,int size)
{
    //服务端
    umask(0);
    createShmHelper(k,size,IPC_CREAT|IPC_EXCL|0666);
}
int getShm(key_t k,int size)
{
    createShmHelper(k,size,IPC_CREAT);
}

因为要保持创建的共享内存是最新的,所以对于服务端来说,第三个参数要传IPC_CREAT | IPC_EXCL,对于客户端只需要传入IPC_CREAT,因此直接设置一个creatshm函数,针对第三个参数设置为flag,可以让2个端口调用同一个函数,只是传参不同。这样代码就高效简洁了。

要注意客户端创建的时候,要给共享内存的权限0666,因为共享内存的权限为0的话,是不能获取共享内存相关结构体和删除共享内存的。

4.2.2:key获取函数

key_t getKey()
{
    key_t k = ftok(PATHNAME,PROJID);
    if(k == -1)
    {
        cerr<<errno<<":"<<strerror(errno)<<endl;
        exit(1);
    }
    return k;
}

 errno的头文件是<cstring>

4.2.3:将key转为16进制接口

string toHex(int x)
{
    char buffer[64];
    snprintf(buffer,sizeof(buffer),"0x%x",x);
    return buffer;
}

 

4.3:server.cc

#include"comm.cpp"
int main()
{   
    key_t k = getKey();
    cout<<"k :"<<toHex(k)<<endl;
    int shmid = createShm(k,gsize);
    cout<<"server shmid:"<<shmid<<endl;
    return 0;
}

4.4:client.cc

#include"comm.hpp"
int main()
{
    key_t k = getKey();
    cout<<"k :"<<toHex(k)<<endl;
    int shmid = getShm(k,gsize);
    cout<<"client shmid:"<<shmid<<endl;
    return 0;
}

4.5:展示

 可以看到同一份共享内存。

前提已经保证了,如何进行通信?就是将两个进程与共享内存挂接上。

5:挂接函数shmat

 第一个参数:共享内存id,也就是共享内存标识

第二个参数:指定连接的地址,可以给nullptr,让操作系统自己完成

第三个参数:取值可能为SHM_RND 或 SHM_RDONLY

返回值就是一块地址,也就是之前提到的,客户端可以拿到共享内存在进程地址空间中的起始地址。

char* attach(int shmid)
{
    char* start = (char*)shmat(shmid,nullptr,0);
    return start;
}

写一段这样的公共代码

int main()
{
    key_t k = getKey();
    cout<<"k :"<<toHex(k)<<endl;
    int shmid = getShm(k,gsize);
    cout<<"client shmid:"<<shmid<<endl;
    char* start = attach(shmid);
    char c = 'A';
    while(c<'Z')
    {
        start[c-'A'] = c;
        c++;
        start[c] = '\0';
        sleep(1);
    }
    return 0;
}
int main()
{   
    key_t k = getKey();
    cout<<"k :"<<toHex(k)<<endl;
    int shmid = createShm(k,gsize);
    cout<<"server shmid:"<<shmid<<endl;
    char* start = attach(shmid);
    int n = 0;
    while(n<=30)
    {
        cout<<"client -> server"<<start<<endl;
        sleep(1);
        n++;
    }

    return 0;
}

这是client和server端的代码。

运行起来后如果发现

说明是之前申请的共享内存没有释放掉,如果我们需要释放共享内存,则必须对共享内存的shmid操作而不是key,类似于打开文件是必须对文件的fd操作而不是inode。

释放命令行指令:ipcrm -m shmid

查询共享内存指::ipcs -m

可以看到成功运行起来。

6:取消挂接 

 使用函数

 参数就是shmat返回的指针,在我们这里就是start。

7:释放共享内存

使用函数

第一个参数是shmid,共享内存标识符

第二个参数是将要采取的动作

第三个参数是指向一个保存着共享内存的模式状态和访问权限的数据结构。一般给nullptr

成功返回0,失败返回-1

 

关于共享内存展示的最终优化代码下一章博客放出。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

前段时间面了15个人,发现这些测试人都有个通病......

前段时间面了15个人&#xff0c;怎么说呢&#xff0c;基本上没有符合要求的&#xff0c;其实一开始瞄准的就是中级的水准&#xff0c;也没指望来大牛&#xff0c;提供的薪资在10-20k&#xff0c;面试的人很多&#xff0c;但平均水平很让人失望。看简历很多都是3年工作经验&…

C++——一种特殊的二叉搜索树之AVL树

目录序言1 AVL树的概念2 AVL树节点的定义3 AVL树的插入是否继续更新依据&#xff1a;子树的高度是否变化4 AVL树的旋转旋转的原则&#xff1a;1. 新节点插入较高左子树的左侧---左左&#xff1a;右单旋2. 新节点插入较高右子树的右侧---右右&#xff1a;左单旋3. 新节点插入较高…

Java基础之File

文章目录一、File的声明二、File的创建2.1 创建一个文件2.2 创建一个文件夹2.3 创建一个多级文件夹三、File的删除四、File的获取与判断4.1 获取一个文件夹孩子层所有文件和文件夹&#xff0c;并存入数组4.2 判断一个File对象是否为文件4.3 判断一个File对象是否为文件夹4.4 判…

Abp框架安全升级指南

本文将从GB/T 28448-2019《信息安全技术 网络安全等级保护测评要求》规定的安全计算环境中解读、摘要若干安全要求&#xff0c;结合Abp框架&#xff0c;对站点进行安全升级。 【身份鉴别】应对登录的用户进行身份标识和鉴别&#xff0c;身份标识具有唯一性&#xff0c;身份鉴别…

实验手册 - 第2周Spark RDD

目录标题1 实验内容实验1实验2实验3实验4实验5实验62 实验总结2.1 Spark应用开发步骤2.2 字符串的split()方法列表解析式2.3 常用的Action操作2.4 常用的Transformation操作2.5 RDD间的Transformation操作1 实验内容 查看当前工作目录 import os os.getcwd()D:\\juniortwo\\s…

【JUC】Java内存模型之JMM

【JUC】Java内存模型之JMM 文章目录【JUC】Java内存模型之JMM1. 概念2. JMM三大特性2.1 可见性2.2 原子性2.3 有序性3. 多线程对变量的读写过程4. 先行发生原则——happens-before4.1 happens-before八条规则4.1.1 次序规则4.1.2 锁定规则4.1.3 volatile变量规则4.1.4 传递规则…

【Unity入门】13.脚本外置参数

【Unity入门】脚本外置参数 大家好&#xff0c;我是Lampard~~ 欢迎来到Unity入门系列博客&#xff0c;所学知识来自B站阿发老师~感谢 &#xff08;一&#xff09;外置脚本参数 &#xff08;1&#xff09;外置自转脚本的速度参数 我们在RotateLogic的时候&#xff0c;为了实现自…

ubuntu虚拟机下搭建zookeeper集群,安装jdk压缩包,搭建Hadoop集群与spark集群的搭建【下篇】

系列文章目录 Hadoop与主机连接以及20版本的Hadoop配置网络的问题_hadoop连不上网 Hadoop升级update命令被锁定的解决方法_hadoop重新初始化被锁住怎么办虚拟机vmware下安装Ubuntu16.04修改屏幕尺寸与更新源&#xff0c;以及对应的安装vim和vim常见的操作命令 文章目录 前言…

ELK部署-实现Nginx日志收集

一、部署ES 1、创建网络下载镜像 docker network create elastic docker pull elasticsearch:7.17.62、目录准备 mkdir /opt/ELK/elastic/{data,config} -p chmod 777 /opt/ELK/elastic/datacat >> /opt/ELK/elastic/config/elasticsearch.yml <<EOF cluster.na…

DFS与BFS寻找图中的所有路径(C++)

文章目录图的存储理论知识数组模拟链表数组模拟邻接表DFS 寻找所有路径代码输入数据对应图输出BFS 寻找所有路径代码输入数据对应图输出备注写在后面图的存储 理论知识 图的存储主要有 2 种方式 邻接表邻接矩阵 邻接矩阵不适合存储稀疏图&#xff0c;本文使用邻接表来存储图 …

运用Navicat 实现 DML(对表的数据进行增删改)

如何使用Navicat呢&#xff1f; 当Navicat配置好后&#xff0c;链接上数据库后。 点击查询后tables中的任意一个新建查询&#xff0c;这时就会跳出一个查询编辑器。 我在初始sql是就创建了stu表。这里就不创建了。 先选择需要的表&#xff0c; select * from 表名; 添加&…

【JAVA】经典面试题:HashMap,Hashtable和ConcurrentHashMap三者之间的区别!!!

本篇的内容是围绕哈希表来展开的&#xff0c;主要是通对HashMap&#xff0c;Hashtable&#xff0c;ConcurrentHashMap三者的特点去了解这它们之间的区别以及运用场景 目录 1. HashMap 2. Hashtable 锁太粗问题&#xff1a; 3. 扩容机制问题 3. ConcurrentHashMap Concurr…

N5183B信号发生器

N5183B N5183B,是德keysight N5183B 主要特性与技术指标信号特征9 kHz &#xff5e; 3 或 6 GHz在 3 GHz 时提供 24 dBm 功率&#xff0c;带有电子衰减器1 GHz 和 20 kHz 偏置时&#xff0c;相位噪声为 -146 dBc≤-73 dBc ACP W-CDMA 64 DPCH 和 <0.4% EVM 160 MHz 802.11…

万字长文解读Stable Diffusion的核心插件—ControlNet

目录 一、介绍 二、使用方法 三、ControlNet结构 1.整体结构 2.ControlLDM 3.Timestep Embedding 4.HintBlock 5.ResBlock 6.SpatialTransformer 7.SD Encoder Block 8.SD Decoder Block 9.ControlNet Encoder Block 10.Stable Diffusion 四、训练 1.准备数据集…

stable-diffusion-webui浅叙

GitHub - AUTOMATIC1111/stable-diffusion-webui: Stable Diffusion web UI 使用Git下载&#xff1a; git clone https://github.com/AUTOMATIC1111/stable-diffusion-webui.git 运行 webui-user.bat : git clone https://github.com/AUTOMATIC1111/stable-diffusion-webui.g…

【NestJs】使用MySQL创建多个实体

如果小伙伴还不会使用nestjs连接数据库的话 可以看我的上一篇文章 NestJs使用连接mysql企业级开发规范 关系 关系是指两个或多个表之间的联系。关系基于每个表中的常规字段&#xff0c;通常包含主键和外键。关系有三种&#xff1a; 名称说明一对一主表中的每一行在外部表中有…

从零到一发布 NPM 包

如果你负责前端的基础能力建设&#xff0c;发布各种功能/插件包犹如家常便饭&#xff0c;所以熟悉对 npm 包的发布与管理是非常有必要的&#xff0c;故此有了本篇总结文章。本篇文章一方面总结&#xff0c;一方面向社区贡献开箱即用的 npm 开发、编译、发布、调试模板&#xff…

【展会邀请】百华与您相约第104届中国劳动保护用品交易会!

重磅消息&#xff01;一场行业极具规模的劳保展 第104届中国劳动保护用品交易会 暨2023中国国际职业安全及健康产业博览会 将于2023.4.13-15在上海新国际博览中心E1-E7馆隆重举办&#xff01; 山东百华鞋业有限公司受邀参展&#xff0c;正在火热筹备中。 百华展位号 2023…

算法:将一个数组旋转k步

题目 输入一个数组如 [1,2,3,4,5,6,7]&#xff0c;输出旋转 k 步后的数组。 旋转 1 步&#xff1a;就是把尾部的 7 放在数组头部前面&#xff0c;也就是 [7,1,2,3,4,5,6]旋转 2 步&#xff1a;就是把尾部的 6 放在数组头部前面&#xff0c;也就是 [6,7,1,2,3,4,5]… 思路 思…

PasteSpider的下载和安装

你是否在纠结于k8s的庞大和复杂&#xff0c;是否在被混论的发布流程搞得焦头烂额。PasteSpider适合你&#xff01;足够小的内存资源消耗(300MB甚至更低&#xff01;)&#xff0c;不需要专业的运维知识&#xff0c;图文操作&#xff0c;支持一键发布&#xff0c;支持自动路由配置…