[Linux打怪升级之路]-system V共享内存
前言
作者:小蜗牛向前冲
名言:我可以接受失败,但我不能接受放弃
如果觉的博主的文章还不错的话,还请
点赞,收藏,关注👀支持博主。如果发现有问题的地方欢迎❀大家在评论区指正
本期学习目标:认识什么是 system V共享内存,认识共享内存的接口函数,学会运用共享内存
目录
一、共享内存的基本原理
1、什么是共享内存
2、共享内存和管道的对比
二、共享内存的系统接口
1、shmget函数(创建共享内存)
2、shmat函数(关联)
3、shmdt函数(去关联)
4、shmctl函数(控制)
三、用共享内存进行通信
1、comm.hpp
2、server.cpp
3、client.cpp
4、现象
一、共享内存的基本原理
1、什么是共享内存
共享内存是一种进程间通信机制,它允许两个或多个进程共享同一块物理内存空间,从而实现数据共享。在共享内存中,进程可以通过读写共享内存的方式来相互通信,而不必进行复杂的管道、消息队列等进程间通信操作。
那我们知道了共享内存,其实就是OS操作系统管理的一块共享物理内存,那共享内存是怎么样实现进程间通信的呢?
下面我们看图来理解
首先我们让操作系统在物理内存中,创建一块共享内存。然后在将创建的内存通过页表映射到进程地址空间,这样 A和B进程就通过共享内存建立起来联系,A进程如果想和B进程通信,只要让A进程往物理内存中写数据,在让B进程读数据就可以了。最后我们不在想让AB进程进行通信,我们只要去关联就可以了,AB进程的关联无非是共享的物理内存,所以我们只要取消二者的映射关系,在释放内存即可。
那这种方式和我们前面将的管道将有什么优缺点吗?
客官别走,且听我细细道来。
2、共享内存和管道的对比
共享内存和管道是两种不同的进程间通信机制,它们各有优势和适用场景。下面是它们的对比:
数据传输方式:
- 共享内存:进程直接访问同一块物理内存,数据在内存中共享。
- 管道:通过缓冲区进行数据传输,数据在缓冲区中依次流动。
通信效率:
- 共享内存:由于直接访问内存,读写效率高,适用于大量数据交换的场景。
- 管道:数据需要经过内核空间,相对较慢,适用于小量数据传输或者不频繁的通信。
数据同步和通信方式:
- 共享内存:需要考虑并发控制和同步问题,通信方式更为灵活,可以使用类似锁、信号量等机制进行同步。
- 管道:基于先进先出的原则,数据流动是单向的,不需要显式的同步操作。
可扩展性:
- 共享内存:多个进程可以同时访问共享内存,适用于多个生产者和消费者的情况。
- 管道:一般情况下,只支持一个生产者和一个消费者,不适用于多个进程之间的数据交换。
综上所述,共享内存适用于大量数据交换、需要高效率和灵活同步的场景,而管道适用于小量数据传输或者不频繁的通信,并且只涉及一个生产者和一个消费者。
二、共享内存的系统接口
1、shmget函数(创建共享内存)
功能:用来创建共享内存
原型: int shmget(key_t key, size_t size, int shmflg);
参数 :
key:这个共享内存段名字
size:共享内存大小
shmflg:由九个权限标志构成,它们的用法和创建文件时使用的mode模式标志是一样
返回值:成功返回一个非负整数,即该共享内存段的标识码(shmid);失败返回-1
key是什么
key是共享内存段的名字,我们要注意他是多少我们不关系,我们关心的是他的作用是能够进行唯一的标识。
虽然我们不关系他是多少,但是我们要传什么key给shmegt,key_t 是一个什么类型。
这里我们先看一个获取k的函数ftok()
。那key_t是个什么类型?
key_t
是一个在Unix/Linux系统中用于表示IPC(进程间通信)键的类型。它被定义为一个整数类型(通常是int
),用于唯一标识共享内存、消息队列和信号量等进程间通信机制。
举例子获取k:
#define PATHNAME "."
#define PROJ_ID 0x66key_t getKey()
{key_t k = ftok(PATHNAME,PROJ_ID);if(k < 0){std::cerr << errno << ":" << strerror(errno) << std::endl;exit(1);}return k;
}
其中的ftok() 函数使用由给定路径名命名的文档的标识(必须引用现有的、可访问的文档)和最不重要的 8 位proj_id(必须为非零)生成一个key_t类型的 System V IPC 密钥
shmflg是什么
shmflg是标志位,用于指定操作共享内存的方式这里我们举例二种最常见的标志位:
IPC_CREAT:如果共享内存不存在就创建,如果存在就获取他。
IPC_EXCL:无法单独使用,IPC_CREAT|IPC_EXCL如果不存在创建共享内存,如果存在就出错返回。
shmget的用法:
#define MAX_SIZE 4096
int getShmHelper(key_t k, int flags)
{int shmid = shmget(k,MAX_SIZE,flags);if(shmid < 0){std::cerr << errno << ":" << strerror(errno) << std::endl;exit(2);}return shmid;
}
2、shmat函数(关联)
功能:将共享内存段连接到进程地址空间
原型 :void *shmat(int shmid, const void *shmaddr, int shmflg);
参数: shmid: 共享内存标识 shmaddr:指定连接的地址 shmflg:它的两个可能取值是SHM_RND和SHM_RDONLY
返回值:成功返回一个指针,指向共享内存第一个节;失败返回-1
这里我们要注意的是返回指针可以认为是共享内存的起始地址。
shmflg:
SHM_RND
:将size
参数舍入到系统页面大小的倍数。这样做可以保证共享内存段的大小是系统页面大小的整数倍,以提高性能。
SHM_RDONLY
:以只读方式打开共享内存段。这意味着进程只能读取共享内存中的数据,不能进行写操作。这个标志通常用于让多个进程共享只读数据的情况
用法:
//返回指是共享内存的开始地址
void* attachShm(int shmid)
{void* start = shmat(shmid,nullptr,0);if((long long)start == -1L){std::cerr << errno << ":" << strerror(errno) <<std::endl;exit(3);}return start;
}
3、shmdt函数(去关联)
功能:将共享内存段与当前进程脱离
原型: int shmdt(const void *shmaddr);
参数 :shmaddr: 由shmat所返回的指针
返回值:成功返回0;失败返回-1 注意:将共享内存段与当前进程脱离不等于删除共享内存段
用法:
void detachShm(void *start)
{if(shmdt(start) == -1){std::cerr <<"shmdt: "<< errno << ":" << strerror(errno) << std::endl;}
}
4、shmctl函数(控制)
功能:用于控制共享内存
原型: int shmctl(int shmid, int cmd, struct shmid_ds *buf);
参数:shmid:由shmget返回的共享内存标识码 cmd:将要采取的动作(有三个可取值) buf:指向一个保存着共享内存的模式状态和访问权限的数据结构
返回值:成功返回0;失败返回-1
这里我们重点关注:参数cmd
IPC_STAT:把shmid_ds结构中的数据设置为共享内存的当前关联值
IPC_SET:在进程有足够权限的前提下,把共享内存的当前值设置为shmid_ds数据结构中给出的值
IPC_RMID:删除共享内存
struct shmid_ds *buf参数保存着共享内存的模式状态和访问权限的数据结构,里面存放这共享内存的共享参数
三、用共享内存进行通信
下面我们将用共享内存实现server和client的通信
1、comm.hpp
我们定义一个comm.hpp的头文件定义server和client共同使用的函数:
#ifndef _COMM_HPP
#define _COMM_HPP#include<iostream>
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/shm.h>
#include<cerrno>
#include<cstring>
#include<cstdio>
#include<cstdlib>#define PATHNAME "."
#define PROJ_ID 0x66#define MAX_SIZE 4096//获取密钥k
key_t getKey()
{key_t k = ftok(PATHNAME,PROJ_ID);if(k < 0){std::cerr << errno << ":" << strerror(errno) << std::endl;exit(1);}return k;
}//调用shmget创建共享内存
int getShmHelper(key_t k, int flags)
{int shmid = shmget(k,MAX_SIZE,flags);if(shmid < 0){std::cerr << errno << ":" << strerror(errno) << std::endl;exit(2);}return shmid;
}//获取shmid标识码
int getShm(key_t k)
{return getShmHelper(k,IPC_CREAT);
}//调用getShmHelper
int createShm(key_t K)
{return getShmHelper(K,IPC_CREAT | IPC_EXCL | 0600);
}//返回指是共享内存的开始地址
void* attachShm(int shmid)
{void* start = shmat(shmid,nullptr,0);if((long long)start == -1L){std::cerr << errno << ":" << strerror(errno) <<std::endl;exit(3);}return start;
}//进行去关联
void detachShm(void *start)
{if(shmdt(start) == -1){std::cerr <<"shmdt: "<< errno << ":" << strerror(errno) << std::endl;}
}//删除共享内存
void delShm(int shmid)
{if(shmctl(shmid,IPC_RMID,nullptr) == -1){std::cerr << errno << ":" << strerror(errno) <<std::endl;}
}#endif
2、server.cpp
这里我们让server进程,打印k和shmid值给我们看一下,并进行创建共享内存,并且进行和client进行通信
#include"comm.hpp"
#include <unistd.h>int main()
{key_t k = getKey();//看看kprintf("key: 0x%x\n",k);//创建共享内存int shmid = createShm(k);printf("shmid: %d\n",shmid);//关联共享内存char *start = (char*)attachShm(shmid);printf("attach success, address start: %p\n", start);const char* message = "hello server,我是clinet正在和你通信";pid_t id = getpid();int cnt = 1;while(true){sleep(5);snprintf(start,MAX_SIZE,"%s[pid:%d][信息标号:%d]",message,id,cnt);}detachShm(start);return 0;
}
3、client.cpp
这里我们让client和server进行通信,server负责接受就可以了
#include"comm.hpp"
#include <unistd.h>int main()
{key_t k = getKey(); printf("key: 0x%x\n", k);int shmid = getShm(k);printf("shmid: %d\n", shmid);//关联共享内存char *start = (char*)attachShm(shmid);printf("attach success, address start: %p\n", start);const char* message = "hello server,我是clinet正在和你通信";pid_t id = getpid();int cnt = 1;while(true){sleep(5);snprintf(start,MAX_SIZE,"%s[pid:%d][信息标号:%d]",message,id,cnt);}//去关联detachShm(start);return 0;
}
4、现象
运行shm_server
运行shm_client
但是当我们第二次在运行./shm_server时候却不行了
这是为什么呢?
我们通过ipcs -m命令查看一下:
ipcs -m
ipcs -m
是一个Unix/Linux系统中的命令,用于列出当前系统中的共享内存段信息。它可以显示已经创建的共享内存段的详细信息,包括标识符、权限、大小、进程ID等。
key
:共享内存段的键值。shmid
:共享内存段的标识符。owner
:创建该共享内存段的用户ID。perms
:共享内存段的权限。bytes
:共享内存段的大小(字节数)。nattch
:连接到该共享内存段的进程数量。status
字段表示共享内存段的状态
其中
status
值及其含义如下:
0
:表示共享内存段当前未被使用或已被释放。dest
:表示共享内存段标记为准备删除状态。这意味着共享内存段即将被销毁,但仍然有进程连接到它,只有当所有连接到该共享内存段的进程都脱离连接时,它才会被完全删除。out
:表示共享内存段处于被卸载状态。这意味着该共享内存段已经被脱离连接,但仍然存在于系统中。可以通过手动操作或进程退出来释放该共享内存段。err
:表示共享内存段状态异常,可能由于系统错误或其他问题导致无法正常访问和管理。
这说明了共享内存生命周期是随操作系统的,不是随进程。用就是说如果我们没有主动调用shmcl函数去控制删除共享内存空间,那么我们后面就要自去删除一下就可以在次运行了。
ipcrm -m shmid
相关文章:

[Linux打怪升级之路]-system V共享内存
前言 作者:小蜗牛向前冲 名言:我可以接受失败,但我不能接受放弃 如果觉的博主的文章还不错的话,还请点赞,收藏,关注👀支持博主。如果发现有问题的地方欢迎❀大家在评论区指正 本期学习目标&…...

STM32不使用 cubeMX实现外部中断
这篇文章将介绍如何不使用 cubeMX完成外部中断的配置和实现。 文章目录 前言一、文件加入工程二、代码解析exti.cexti.hmain.c 注意:总结 前言 实验开发板:STM32F103C8T6。所需软件:keil5 , cubeMX 。实验目的:如何不…...

Nautilus Chain 与 Coin98 生态达成合作,加速 Zebec 生态亚洲战略进
目前,行业内首个模块化 Layer3 架构公链 Nautilus Chain 已经上线主网,揭示了模块化区块链领域迎来了全新的进程。在主网上线后,Nautilus Chain 将扮演 Zebec 生态中最重要的底层设施角色,并将为 Zebec APP 以及 Zebec Payroll 规…...

method.isAnnotationPresent(Xxx.class)一直为null
package com.dj.springtest.aspect;import com.dj.springtest.annotation.RequireRoles; import lombok.extern.slf4j.Slf4j; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.s…...

基于CNN实现谣言检测 - python 深度学习 机器学习 计算机竞赛
文章目录 1 前言1.1 背景 2 数据集3 实现过程4 CNN网络实现5 模型训练部分6 模型评估7 预测结果8 最后 1 前言 🔥 优质竞赛项目系列,今天要分享的是 基于CNN实现谣言检测 该项目较为新颖,适合作为竞赛课题方向,学长非常推荐&am…...

MySQL——七、MySQL备份恢复
MySQL 一、MySQL日志管理1、MySQL日志类型2、错误日志3、通用查询日志4、慢查询日志5、二进制日志5.1 开启日志5.2 二进制日志的管理5.3 日志查看5.4 二进制日志还原数据 二、MySQL备份1、备份类型逻辑备份优缺点 2、备份内容3、备份工具3.1 MySQL自带的备份工具3.2 文件系统备…...

iOS如何实现语音转文字功能?
1.项目中添加权限 Privacy - Speech Recognition Usage Description : 需要语音识别权限才能实现语音转文字功能 2.添加头文件 #import <AVFoundation/AVFoundation.h> #import<Speech/Speech.h> 3.实现语音转文字逻辑: 3.1 根据wav语音文件创建请求 SFSpeechU…...

【下载器篇】获取微软应用商店应用安装包的方法
【下载器篇】获取微软应用商店应用安装包的方法 微软应用商店历史版本应用下载方法,部分历史版本无法搜索到—【蘇小沐】 文章目录 【下载器篇】获取微软应用商店应用安装包的方法1.实验环境 (一)微软商店的在线链接生成器1、复制该应用的在…...
云安全—集群攻击入口攻与防
0x00 前言 说到云安全肯定不能避免的是集群相关的内容,最出色的就是Kubernetes,也就是k8s。当然docker相关的内容也算是集群的一部分。但是docker容器本身的问题还是归属于容器本身。 0x01 概述 在集群攻击入口处的内容主要为: 应用安全恶…...
“传统”开发与AI开发的区别与联系(更新了GPT3.5的反馈)
1、传统开发的算法和软件整体,也可以看成是一个“大模型”,其中有不同层次的处理,最终能够完成从输入到输出的计算,不过,其中的计算都是人工定义的,一般依赖于研究成果的应用。研究成果在实际中的应用处理。…...

Unity 文字显示动画(2)
针对第一版的优化,自动适配文字大小,TextMeshPro可以拓展各种语言。第一版字母类语言效果更好。 using System.Collections; using System.Collections.Generic; using TMPro; using UnityEngine; using UnityEngine.UI;public partial class TextBeat…...
力扣每日一题53:最大子数组和
题目描述: 给你一个整数数组 nums ,请你找出一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。 子数组 是数组中的一个连续部分。 示例 1: 输入:nums [-2,1,-3,4,-1,2,1,…...

图论04-【无权无向】-图的广度优先遍历
文章目录 1. 代码仓库2. 广度优先遍历图解3.主要代码4. 完整代码 1. 代码仓库 https://github.com/Chufeng-Jiang/Graph-Theory 2. 广度优先遍历图解 3.主要代码 原点入队列原点出队列的同时,将与其相邻的顶点全部入队列下一个顶点出队列出队列的同时,将…...
layui的一些问题
为什么table.render, ins1.config有时候获取的值是上一次的?例如ins1.conf.page.curr? 这是一段table.render代码 let ins1 table.render({...})一般情况下ins1.conf可以获得表格的当前页,页数等;但是有时候获得的页数是上一次的;主要是因为在table.reload后没有继续赋值的…...

设计模式_中介者模式
中介者模式 介绍 设计模式定义案例问题堆积在哪里解决办法中介者代替了多个对象之间的互动 使对象1 2 3 之间的互动 变为: 对象1->中介 对象2->中介 对象3->中介好友之间 约饭好友1 通知 好友2 -3 -4 等等加一个群 谁想吃饭就 通知一下 类图 代码 角色 …...

062:mapboxGL通过jumpTo方式跳转到某位置
第062个 点击查看专栏目录 本示例的目的是介绍演示如何在vue+mapbox中通过jumpTo方式跳转到某位置。 直接复制下面的 vue+mapbox源代码,操作2分钟即可运行实现效果 文章目录 示例效果配置方式示例源代码(共122行)相关API参考:专栏目标示例效果 配置方式 1)查看基础设置…...
学成在线第一天-课程内容管理服务搭建以及查询课程接口设计
目录 一、搭建课程内容管理服务 二、设计接口 三、面试题 四、总结 一、搭建课程内容管理服务 没什么好说的,直接就是创建内容模块 然后这个继承父模块,然后再课程内容模块下面创建三个子模块,model、sevice、controller model依赖base…...

4.7 IP多播
思维导图: **4.7.1 IP多播的基本概念** --- **1. 定义和背景** - IP多播:从一个源点发送信息至多个终点的技术。 - 1988年:Steve Deering首次提及IP多播。 - 1992年:IETF进行了首次IP多播试验,当时有20个网点参与。 …...
XML与html解析,区别,如何使用
目录 简介: HTML(超文本标记语言): 如何使用HTML: XML(可扩展标记语言): 如何使用XML: 区别: 简介: XML(可扩展标记语言)和 HTMLÿ…...

【广州华锐互动】利用VR开展建筑塔吊安全操作学习的好处?
随着科技的不断发展,虚拟现实(VR)技术已经逐渐渗透到各个领域,为人们的生活带来了前所未有的便利。在工程教育领域,VR建筑塔吊安全操作学习作为一种新型的教学手段,正逐渐成为提高教学质量和培养高素质工程…...
java 实现excel文件转pdf | 无水印 | 无限制
文章目录 目录 文章目录 前言 1.项目远程仓库配置 2.pom文件引入相关依赖 3.代码破解 二、Excel转PDF 1.代码实现 2.Aspose.License.xml 授权文件 总结 前言 java处理excel转pdf一直没找到什么好用的免费jar包工具,自己手写的难度,恐怕高级程序员花费一年的事件,也…...
工程地质软件市场:发展现状、趋势与策略建议
一、引言 在工程建设领域,准确把握地质条件是确保项目顺利推进和安全运营的关键。工程地质软件作为处理、分析、模拟和展示工程地质数据的重要工具,正发挥着日益重要的作用。它凭借强大的数据处理能力、三维建模功能、空间分析工具和可视化展示手段&…...
macOS多出来了:Google云端硬盘、YouTube、表格、幻灯片、Gmail、Google文档等应用
文章目录 问题现象问题原因解决办法 问题现象 macOS启动台(Launchpad)多出来了:Google云端硬盘、YouTube、表格、幻灯片、Gmail、Google文档等应用。 问题原因 很明显,都是Google家的办公全家桶。这些应用并不是通过独立安装的…...

智能仓储的未来:自动化、AI与数据分析如何重塑物流中心
当仓库学会“思考”,物流的终极形态正在诞生 想象这样的场景: 凌晨3点,某物流中心灯火通明却空无一人。AGV机器人集群根据实时订单动态规划路径;AI视觉系统在0.1秒内扫描包裹信息;数字孪生平台正模拟次日峰值流量压力…...
【碎碎念】宝可梦 Mesh GO : 基于MESH网络的口袋妖怪 宝可梦GO游戏自组网系统
目录 游戏说明《宝可梦 Mesh GO》 —— 局域宝可梦探索Pokmon GO 类游戏核心理念应用场景Mesh 特性 宝可梦玩法融合设计游戏构想要素1. 地图探索(基于物理空间 广播范围)2. 野生宝可梦生成与广播3. 对战系统4. 道具与通信5. 延伸玩法 安全性设计 技术选…...

云原生玩法三问:构建自定义开发环境
云原生玩法三问:构建自定义开发环境 引言 临时运维一个古董项目,无文档,无环境,无交接人,俗称三无。 运行设备的环境老,本地环境版本高,ssh不过去。正好最近对 腾讯出品的云原生 cnb 感兴趣&…...

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

20个超级好用的 CSS 动画库
分享 20 个最佳 CSS 动画库。 它们中的大多数将生成纯 CSS 代码,而不需要任何外部库。 1.Animate.css 一个开箱即用型的跨浏览器动画库,可供你在项目中使用。 2.Magic Animations CSS3 一组简单的动画,可以包含在你的网页或应用项目中。 3.An…...
【学习笔记】erase 删除顺序迭代器后迭代器失效的解决方案
目录 使用 erase 返回值继续迭代使用索引进行遍历 我们知道类似 vector 的顺序迭代器被删除后,迭代器会失效,因为顺序迭代器在内存中是连续存储的,元素删除后,后续元素会前移。 但一些场景中,我们又需要在执行删除操作…...

Ubuntu Cursor升级成v1.0
0. 当前版本低 使用当前 Cursor v0.50时 GitHub Copilot Chat 打不开,快捷键也不好用,当看到 Cursor 升级后,还是蛮高兴的 1. 下载 Cursor 下载地址:https://www.cursor.com/cn/downloads 点击下载 Linux (x64) ,…...