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

Linux进程间通信之共享内存

📟作者主页:慢热的陕西人

🌴专栏链接:Linux

📣欢迎各位大佬👍点赞🔥关注🚓收藏,🍉留言

本博客主要内容讲解共享内存原理和相关接口的介绍,以及一个案例的展示

文章目录

  • system V共享内存
    • 1.共享内存的原理
    • 2.直接写代码--编写代码进行原理介绍
      • 2.1shmget接口的介绍
      • 2.2key值为什么需要用ftok生成
      • 2.3ftok接口
      • 2.3三个命令
      • 2.4shmat和shmdt
    • 3.通信测试
    • 4.代码

system V共享内存

共享内存属于是,操作系统单独为我们设计的进程间通信方式,最后慢慢演变成为了systemV的一种标准。它是属于文件系统之外的,但是它属于专门为了通信而设计的内核模块,我们称为systemV的IPC通信机制。

但是进程是具有独立性的,所以我们要实现进程间的通信,首先第一点就是要做到两个进程看到同一份资源

共享内存区是最快的IPC形式。一旦这样的内存映射到共享它的进程的地址空间,这些进程间数据传递不再涉及到内核,换句话说是进程不再通过执行进入内核的系统调用来传递彼此的数据。

1.共享内存的原理

首先我们用一个例子来介绍:首先存在两个进程,我们画出对应的地址空间和页表。首先和我们之前的知识一样,进程内部的PCB内部有一个指针指向其对应的内存空间,然后地址空间和物理内存的映射关系存储在每个进程对应的页表中,唯独不同的是这时候页表映射到物理内存空间上却是同一份空间并且这个空间就是我们所谓的共享内存。

宏观控制共享内存的三个步骤:

  • ①创建
  • ②关联进程和取消关联
  • ③释放共享内存

image-20231130191729999

2.直接写代码–编写代码进行原理介绍

2.1shmget接口的介绍

  • 作用:用于申请system V的共享内存空间

  • 参数key :这个参数由我们的另一个接口生成:ftok:关于这个接口后面会介绍

  • 参数size :申请共享内存空间的大小

  • 参数 shmflg:

    这里我们介绍其中的两个:

    a. IPC_CREAT: 创建一个共享内存,如果共享内存不存在,就创建,如果已经存在,获取已经存在的共享内存并返回。

    b. IPC_EXCL:不能单独使用,一般要配合IPC_CREAT来使用,含义是创建一个共享内存,如果共享内存不存在,就创建,如果已经存在,则立马出错返回 – 如果创建成功,对应的共享内存一定是最新的共享内存!

  • 返回值:成功返回对应的共享内存标识符,失败的话返回-1,并且errno被设置。

image-20231130195042509

2.2key值为什么需要用ftok生成

首先系统中可以用shm通信,是不是只能有一对进程使用共享内存呢?可以!->所以,在任何一个时刻,可能有多个共享内存在被用来进行通信->所以系统中一定会存在很多shm同时存在->OS要不要整体管理所有的共享内存呢?要!-> OS如何管理多个shm内存呢?先描述,再组织。所以共享内存,不是我们想象的那样,只要在内存中开辟空间即可,系统也要为了关了shm,构建对应的描述共享内存的结构体对象!!

共享内存 = 共享内存的内核数据结构(伪代码:struct shm) + 真正开辟的内存空间。

2.3ftok接口

  • 参数pathname:路径字符串
  • 参数proj_id:项目id

image-20231130213324725

在操作系统内部就是将一块块共享内存通过这种方式组织起来的,那么进程调用ftok通过pathname和proj_id来生成对应的key(也就是申请对应的共享内存空间),那么我们的进程B就可以通过对应的key来寻找对应的共享内存空间。从而实现进程间通信的本质:两个进程看到同一块资源,所以这个key本质是在内核中使用的。

image-20231130215301165

2.3三个命令

  • ipcs -m

    查看系统中存在的共享内存:

    image-20231204172852789

  • ipcrm -m shmid

    删除shmid所对应的共享内存,共享内存的声明周期不随进程,随OS。

    image-20231204173020261

  • shmctl

    这是一个函数接口:用来查看共享内存的一些相关属性,前提是我们执行这个进程的用户具有查看当前共享内存属性的权限,否则无法查看,一般sudo运行即可。或者创建时权限修改为066即可.

    image-20231204203451118

    代码:

        struct shmid_ds ds;int n = shmctl(shmid, IPC_STAT, &ds);if(n == -1){cerr << errno << ":" << strerror(errno) << endl;exit(3);}cout << "prem:" << toHex(ds.shm_perm.__key) << endl;cout << "creater pid :" << ds.shm_cpid << ":" << getpid() << endl;
    

    运行效果:

    image-20231204203711729

2.4shmat和shmdt

这两个接口相关的是nttach参数,他表示的有多少个进程和当前的共享内存挂载的。

  • shmat

用于进程和共享内存产生关联,非常类似于malloc,返回一个void指针,一般我们把这个指针强制转换成char*;

image-20231205133313831

它内部也有一些参数,值得我们去学习和研究:

第一个参数我们已经很熟悉了共享内存描述符是个整数。

  • shmaddr:

    文档中的大概含义是,假如我们传入的是nullptr,那么操作系统就会自动帮我们分配一个未被使用过的合适的地址去链接这份共享内存

    如果shmaddr不为空,并且shmflg中指定了SHM_RND,则连接发生在地址上,并且该地址等于shmaddr,并四舍五入到最接近SHMLBA的倍数。否则shmadr必须是一个与页面对齐的地址,在这个地址上发生附加操作。

    image-20231205134727851

  • shmflg中的一些:

比如:SHM_RDONLY

image-20231205134520832

  • shmdt

    用于进程和对应的共享内存取消关联,相当于我们c语言当时学习的动态内存管理部分的free函数。

    image-20231205170541704

3.通信测试

那么好了总体来说我们要做四步:我们直接把这四步封装成一个类Init;

①获取key

②通过k获取shmid

③链接共享内存

④断开共享内存

#define SERVER 0x1
#define CLIENT 0x2class Init
{//构造函数
public:Init(int T) :type(T){//1.创建keykey_t k = getKey();//2.获取shmidif(type == SERVER) shmid = creatShm(k, gsize);else shmid = getShm(k, gsize);//3.链接共享内存start = attachShm(shmid);}~Init(){//1.切断共享内存dettachShm(start);//2.释放共享内存if(type == SERVER) delShm(shmid);}char* getstart(){return start;}private:char* start; //共享内存的地址int type;  //辨别对象是server还是clientint shmid; //共享内存标识符
};

运行结果:

在这里插入图片描述

4.代码

server.cc

#include"comm.hpp"int main()
{Init server = Init(SERVER);//通信char* start = server.getstart();//输出从共享内存中读取到的信息int n = 0;while(n <= 30){cout << "client->server #" << start << endl;sleep(1);n++; }//拓展内容//1.client写完了,才通知让server读取,刚开始,一定先让client运行,一个管道//2.命名管道带进来//3.client写完了,才通知让server读取,读取完了,才让client进行写入,两个管道return 0;
}

client.cc

#include"comm.hpp"int main()
{Init client = Init(CLIENT);//通信char* start = client.getstart();char c = 'A';while(c <= 'Z'){start[c - 'A'] = c;c++;start[c - 'A'] = '\0';sleep(1);}return 0;
}

comm.cpp

#ifndef COMM_HPP
#define COMM_HPP#include<iostream>
#include<sys/ipc.h>
#include<sys/shm.h>
#include<cerrno>
#include<string.h>
#include<unistd.h>
#include<sys/stat.h>
#include<cassert>
#include<sys/types.h>using namespace std;//路径名称
#define PATHNAME "."
//项目id
#define PROJID 0x6666
//共享内存大小
#define gsize 4096//获取key
key_t getKey()
{//用ftok函数获取keykey_t k = ftok(PATHNAME, PROJID);if(k == -1){cerr << errno << ":" << strerror(errno) << endl;exit(1);}return k;
}string toHex(key_t k)
{char buffer[64];snprintf(buffer, sizeof(buffer),"0x%x", k);return buffer;
}static int creatShmHeaper(key_t k, int size, int flag)
{ int shmid = shmget(k, size, flag);if(shmid == -1){cerr << errno << ":" << strerror(errno) << endl;exit(2);}return shmid;
}//创建共享内存
int creatShm(key_t k, size_t size)
{umask(0);return creatShmHeaper(k, size, IPC_CREAT | IPC_EXCL | 0666);
}//获取共享内存
int getShm(key_t k, size_t size)
{return creatShmHeaper(k, size, IPC_CREAT);
}//删除shmid
void delShm(int shmid)
{int n = shmctl(shmid, IPC_RMID, nullptr);assert(n != -1);(void)n;
}char* attachShm(int shmid)
{char* start = (char*)shmat(shmid, nullptr, 0);return start;
}void dettachShm(char* start)
{int n = shmdt(start);assert(n != -1);(void)n;
}#define SERVER 0x1
#define CLIENT 0x2class Init
{//构造函数
public:Init(int T) :type(T){//1.创建keykey_t k = getKey();//2.获取shmidif(type == SERVER) shmid = creatShm(k, gsize);else shmid = getShm(k, gsize);//3.链接共享内存start = attachShm(shmid);}~Init(){//1.切断共享内存dettachShm(start);//2.释放共享内存if(type == SERVER) delShm(shmid);}char* getstart(){return start;}private:char* start; //共享内存的地址int type;  //辨别对象是server还是clientint shmid; //共享内存标识符
};#endif

到这本篇博客的内容就到此结束了。
如果觉得本篇博客内容对你有所帮助的话,可以点赞,收藏,顺便关注一下!
如果文章内容有错误,欢迎在评论区指正

在这里插入图片描述

相关文章:

Linux进程间通信之共享内存

&#x1f4df;作者主页&#xff1a;慢热的陕西人 &#x1f334;专栏链接&#xff1a;Linux &#x1f4e3;欢迎各位大佬&#x1f44d;点赞&#x1f525;关注&#x1f693;收藏&#xff0c;&#x1f349;留言 本博客主要内容讲解共享内存原理和相关接口的介绍&#xff0c;以及一个…...

lv11 嵌入式开发 RTC 17

目录 1 RTC简介 ​编辑2 Exynos4412下的RTC控制器 2.1 概述 2.2 特征 2.3 功能框图 3 寄存器介绍 3.1 概述 3.2 BCD格式的年月日寄存器 3.3 INTP中断挂起寄存器 3.4 RTCCON控制寄存器 3.5 CURTICCNT 作为嘀嗒定时器使用的寄存器 4 RTC编程 5 练习 1 RTC简介 RTC(…...

c语言指针详解(上)

目录 一、指针的基本概念和用法 二、指针运算 2.1 指针的自增和自减运算 2.2 指针的自增和自减运算 三、数组和指针 四、指针和函数 4.1 在函数中使用指针作为参数和返回值 4.1.1 使用指针作为函数参数 4.1.2 使用指针作为函数返回值 4.2 指针参数的传值和传引用特性 4.2.1 指针…...

如何删除mac苹果电脑上面的流氓软件?

在使用苹果电脑的过程中&#xff0c;有时候我们也会遇到一些不需要的软件。无论是因为不再需要&#xff0c;或者是为了释放磁盘空间&#xff0c;删除这些软件是很重要的。本文将为大家介绍怎样删除苹果电脑上的软件&#xff01; CleanMyMac X全新版下载如下: https://wm.make…...

WordPress(11)给文章添加预计阅读时长

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言一、文件配置二、代码块1.引入库2.配置 single.php三、效果图前言 提示:这里可以添加本文要记录的大概内容: 例如:随着人工智能的不断发展,机器学习这门技术也越来越重要,很多人都开启了…...

周周爱学习之快速排序

快速排序&#xff0c;顾名思义&#xff0c;快速排序是一种速度非常快的一种排序算法 平均时间复杂度为O(),最坏时间复杂度为O()数据量较大时&#xff0c;优势非常明显属于不稳定排序 1.算法描述 每一轮排序选择一个基准点&#xff08;pivot&#xff09;进行分区 让小于基准点…...

国产接口测试工具APIpost

说实话&#xff0c;了解APIpost是因为&#xff0c;我的所有接口相关的文章下&#xff0c;都有该APIpost水军的评论&#xff0c;无非就是APIpost是中文版的postman&#xff0c;有多么多么好用&#xff0c;虽然咱也还不是什么啥网红&#xff0c;但是不知会一声就乱在评论区打广告…...

MySQL电商管理系统练习题及答案

一 、表结构 用户表(user)&#xff1a;id(主键)、username、password、email、phone、age商品表(product)&#xff1a;id(主键)、name、price、stock、description订单表(order)&#xff1a;id(主键)、user_id(外键&#xff0c;关联用户表)、total_price、status、create_time…...

每日3道PWN(第二天)

ciscn_2019_n_1 参考&#xff1a; [BUUCTF-pwn]——ciscn_2019_n_1-CSDN博客 [BUUCTF]PWN5——ciscn_2019_n_1_ciscn_2019_n_4-CSDN博客 BUUCTF—ciscn_2019_n_1 1-CSDN博客 checksec一下 64位栈溢出 按f5查看main函数&#xff0c;双击可疑函数 发现含有命令执行的且发现fl…...

SAP STMS传输请求

一、概述 一般SAP项目上都会有六套系统&#xff0c;分别是&#xff1a; 测试环境-DEV系统 主要由100&#xff1a;沙盘系统&#xff1a;用于业务顾问配置 200&#xff1a;开发系统&#xff1a;用于开发ABAP写代码 300&#xff1a;测试系统&#xff1a;主要是单元测试、顾问自己…...

L1-009:N个数求和

目录 ⭐题目描述⭐ ⭐分析 ⭐程序代码 运行结果 ⭐文案分享⭐ ⭐题目描述⭐ 本题的要求很简单&#xff0c;就是求N个数字的和。麻烦的是&#xff0c;这些数字是以有理数分子/分母的形式给出的&#xff0c;你输出的和也必须是有理数的形式。 输入格式&#xff1a; 输入第一行给出…...

当发送“Hello,World”时,channel发生了什么?

一、Netty概述 1.Netty是什么&#xff1f; Netty 是一个异步的、基于事件驱动的网络应用框架&#xff0c;用于快速开发可维护、高性能的网络服务器和客户端。 2.Netty的地位怎么样&#xff1f; Netty 在 Java 网络应用框架中的地位就好比&#xff1a;Spring 框架在 JavaEE …...

服务器运行情况及线上排查问题常用命令

一、top命令 指令行&#xff1a; top返回&#xff1a; 返回分为两部分 &#xff08;一&#xff09;系统概览&#xff0c;见图知意 以下是几个需要注意的参数 1、load average&#xff1a; 系统负载&#xff0c;即任务队列的平均长度。三个数值分别为 1分钟、5分钟、15分…...

Hadoop学习笔记(HDP)-Part.18 安装Flink

目录 Part.01 关于HDP Part.02 核心组件原理 Part.03 资源规划 Part.04 基础环境配置 Part.05 Yum源配置 Part.06 安装OracleJDK Part.07 安装MySQL Part.08 部署Ambari集群 Part.09 安装OpenLDAP Part.10 创建集群 Part.11 安装Kerberos Part.12 安装HDFS Part.13 安装Ranger …...

LeetCode56. 合并区间

&#x1f517;:【贪心算法&#xff0c;合并区间有细节&#xff01;LeetCode&#xff1a;56.合并区间-哔哩哔哩】 class Solution { public:vector<vector<int>> merge(vector<vector<int>>& intervals) {if(intervals.size()0){return intervals;…...

解决typescript报错:找不到名称xxx

现象&#xff1a; 原因&#xff1a;在同时导入默认导出和命名导出时&#xff0c;默认导出必须放在命名导出之前 下面的就是原始文件&#xff1a; 默认导出指&#xff1a; export default导出类型&#xff0c; import时无需大括号 命名导出指&#xff1a; 仅有export关键字…...

UVM中封装成agent

在验证平台中加入monitor时&#xff0c;看到driver和monitor之间的联系&#xff1a;两者之间的代码高度相似。其本质是因为二者 处理的是同一种协议&#xff0c;在同样一套既定的规则下做着不同的事情。由于二者的这种相似性&#xff0c;UVM中通常将二者封装在一起&#xff0c;…...

OSI七层模型与TCP/IP四层模型

一、OSI七层模型简述 OSI 模型的七层是什么&#xff1f;在 OSI 模型中如何进行通信&#xff1f;OSI 模型有哪些替代方案&#xff1f; TCP/IP 模型关于专有协议和模型的说明 二、七层模型详解&#xff08;DNS、CDN、OSI&#xff09; 状态码DNS nslookup命令 CDN whois命令 …...

QT 中 QProgressDialog 进度条窗口 备查

基础API //两个构造函数 QProgressDialog::QProgressDialog(QWidget *parent nullptr, Qt::WindowFlags f Qt::WindowFlags());QProgressDialog::QProgressDialog(const QString &labelText, const QString &cancelButtonText, int minimum, int maximum, QWidget *…...

学习ShardingSphere前置知识

学习ShardingSphere前置准备知识 一. SPI SPI&#xff08;Service Provider Interface&#xff09;是一种Java的扩展机制&#xff0c;用于实现组件之间的松耦合。在SPI模型中&#xff0c;服务提供者&#xff08;Service Provider&#xff09;定义了一组接口&#xff0c;而服务…...

【算法训练营Day07】字符串part1

文章目录 反转字符串反转字符串II替换数字 反转字符串 题目链接&#xff1a;344. 反转字符串 双指针法&#xff0c;两个指针的元素直接调转即可 class Solution {public void reverseString(char[] s) {int head 0;int end s.length - 1;while(head < end) {char temp …...

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…...

什么?连接服务器也能可视化显示界面?:基于X11 Forwarding + CentOS + MobaXterm实战指南

文章目录 什么是X11?环境准备实战步骤1️⃣ 服务器端配置(CentOS)2️⃣ 客户端配置(MobaXterm)3️⃣ 验证X11 Forwarding4️⃣ 运行自定义GUI程序(Python示例)5️⃣ 成功效果![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/55aefaea8a9f477e86d065227851fe3d.pn…...

RNN避坑指南:从数学推导到LSTM/GRU工业级部署实战流程

本文较长&#xff0c;建议点赞收藏&#xff0c;以免遗失。更多AI大模型应用开发学习视频及资料&#xff0c;尽在聚客AI学院。 本文全面剖析RNN核心原理&#xff0c;深入讲解梯度消失/爆炸问题&#xff0c;并通过LSTM/GRU结构实现解决方案&#xff0c;提供时间序列预测和文本生成…...

安全突围:重塑内生安全体系:齐向东在2025年BCS大会的演讲

文章目录 前言第一部分&#xff1a;体系力量是突围之钥第一重困境是体系思想落地不畅。第二重困境是大小体系融合瓶颈。第三重困境是“小体系”运营梗阻。 第二部分&#xff1a;体系矛盾是突围之障一是数据孤岛的障碍。二是投入不足的障碍。三是新旧兼容难的障碍。 第三部分&am…...

MySQL:分区的基本使用

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

Sklearn 机器学习 缺失值处理 获取填充失值的统计值

💖亲爱的技术爱好者们,热烈欢迎来到 Kant2048 的博客!我是 Thomas Kant,很开心能在CSDN上与你们相遇~💖 本博客的精华专栏: 【自动化测试】 【测试经验】 【人工智能】 【Python】 使用 Scikit-learn 处理缺失值并提取填充统计信息的完整指南 在机器学习项目中,数据清…...

【UE5 C++】通过文件对话框获取选择文件的路径

目录 效果 步骤 源码 效果 步骤 1. 在“xxx.Build.cs”中添加需要使用的模块 &#xff0c;这里主要使用“DesktopPlatform”模块 2. 添加后闭UE编辑器&#xff0c;右键点击 .uproject 文件&#xff0c;选择 "Generate Visual Studio project files"&#xff0c;重…...

OCR MLLM Evaluation

为什么需要评测体系&#xff1f;——背景与矛盾 ​​ 能干的事&#xff1a;​​ 看清楚发票、身份证上的字&#xff08;准确率>90%&#xff09;&#xff0c;速度飞快&#xff08;眨眼间完成&#xff09;。​​干不了的事&#xff1a;​​ 碰到复杂表格&#xff08;合并单元…...