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

systemV共享内存

systemV共享内存

共享内存区是最快的IPC形式。共享内存的大小一般是4KB的整数倍,因为系统分配共享内存是以4KB为单位的(Page)!4KB也是划分内存块的基本单位。

之前学的管道,是通过文件系统来实现让不同的进程看到同一份资源,那有没有不通过文件来实现进程间通信的呢?有!MMU这些

原理

PCB、进程地址空间、页表是每个进程各有一份的【这部分是进程】,文件系统是一个独立的,对进程来说只有一份。

在这里插入图片描述

操作步骤

  1. 创建共享内存:为了实现进程间通信,用户通过系统调用接口在物理内存申请一块内存空间[物理内存块+共享内存相关属性struct_shm]
  2. 进程和共享内存挂接:系统将创建好的内存映射到进程的地址空间,然后交给对应进程的PCB-task_struct。
  3. 断开通信的操作:a.去关联:先取消映射关系;b.释放内存:释放该块物理内存。

malloc能申请物理内存的空间,也能为某进程创建单一的映射关系,为什么不用它呢?

malloc是做不到的!因为malloc出来的映射关系是单一的,不同的malloc之后返回的起始地址都是不一样的,无法共享。

要明确把握的概念

  1. 共享内存是一种进程间通信方式,不是内存!所有想通信的进程都可以采用。
  2. 操作系统在同一时间可以存在很多的共享内存
  3. 共享内存是专门设计的用于IPC的,故有专门的接口

概念

让不同的进程看到同一块内存空间。

查看ipc-systemV资源的指令

查看ipc资源ipcs -m-m表示共享内存,-q消息队列

[yyq@VM-8-13-centos 2023_02_27_SharedMemory]$ ipcs -m------ Shared Memory Segments --------
key        shmid      owner      perms      bytes      nattch     status

systemV版本的共享内存的生命周期是随OS的,不随进程!所以一定要记得及时释放资源。注意:消息队列等方式的共享内存就是随进程的。

命令行删除共享内存ipcrm -m shmid

while :; do ipcs -m; sleep 1; done

函数接口

ftok()函数 得到key

#include <sys/types.h>
#include <sys/ipc.h>
原型key_t ftok(const char *pathname, char proj_id);//路径名的指针pathname,自己写的8bits的非0数字proj_id
返回值成功返回一个key值;失败返回-1
Today  proj_id  is  an  int, but still only 8 bits are used.  Typical usage has an ASCII character proj_id, that is why the behavior is said to be undefined when proj_id is zero.

key保证进程看到同一块共享内存!能进行唯一性标识。key就是32位的int。

shmget()函数 得到shmid

#include <sys/ipc.h>
#include <sys/shm.h>
功能:用来创建共享内存
原型int shmget(key_t key, size_t size, int shmflg);
参数key:ftok()函数返回值,是共享内存段名字,保证该块共享内存的唯一性size:共享内存大小shmflg:由九个权限标志构成,它们的用法和创建文件时使用的mode模式标志是一样的IPC_CREAT 如果共享内存不存在,就创建;存在,则返回地址IPC_EXCL 无法单独使用,要与IPC_CREATE一起用。如果共享内存不存在,就创建;如果存在,就出错返回-->如果创建成功,就一定是一个新的共享内存
返回值成功返回一个非负整数,即该共享内存段的标识码;失败返回-1

IPC_CREAT、IPC_EXCL本质是宏,用二进制标志位的方式来表示选项。

需要创建共享内存的进程用IPC_CREAT | IPC_EXCL | 0600,后续要和该进程通信的进程使用IPC_CREATE【类似于父进程来创建匿名/命名管道,子进程直接用】。0600表示权限,可以看到perms会随之变化,perms为0,挂接会失败。

**共享内存的大小一般要取页表大小(4096字节)的整数倍。**建议为4KB的整数倍,因为系统分配共享内存是以4KB为单位的!4KB也是划分内存块的基本单位。

shmat()函数 进程和共享内存挂接

at-attach

功能:将共享内存段连接到进程地址空间
原型void *shmat(int shmid, const void *shmaddr, int shmflg);
参数shmid: 共享内存标识shmaddr:指定连接的地址==NULL:核心自动选择一个地址!=NULL且shmflg!=SHM_RND:以shmaddr为链接地址!=NULL且shmflg==SHM_RND:连接的地址会自动向下调整为SHMLBA的整数倍。公式:shmaddr-(shmaddr % SHMLBA)shmflg==SHM_RDONLY:连接操作用来只读共享内存shmflg:它的两个可能取值是SHM_RND和SHM_RDONLY
返回值成功返回一个指针,指向共享内存第一个节;失败返回-1//假设void* ret为返回值,则判断条件为(long long)ret == -1L[强转为int的前提条件:系统为32为系统!但是linux是64位系统,指针是8个字节,而int是4字节,编译会报错]

理解key使共享内存具有唯一性,以及key和shmid间的关系和区别

ftok()函数返回值是key和shmget()函数返回值是shmid。

首先,共享内存=物理内存块+共享内存相关属性(即操作系统为管理共享内存建立的一个结构体)。

创建共享内存的时候如何保证共享内存在系统中的唯一性?通过key来实现,key类似于fd,通过shmge()t函数将key设置为struct shm{ key_t k; }k上,当共享内存属性的k一样时,就能进入同一块内核内存空间。

区别:shmid类似于fd,供用户使用,key类似于inode,用于标定系统的共享内存,是内核级的描述符;即key是系统层面用的,shmid是给用户用的,是为了解耦,fd和inode同理。

注意:成功挂接后,通过ipcs -m命令查看该块共享内存的属性,可以看到nattch的数字会++.

shmdt()函数 去关联

dt–detach

#include <sys/types.h>
#include <sys/shm.h>
功能:将共享内存段与当前进程脱离
原型int shmdt(const void *shmaddr);
参数shmaddr: 由shmat所返回的指针
返回值成功返回0;失败返回-1
注意:将共享内存段与当前进程脱离不等于删除共享内存段

shmctl()函数 删除共享内存段/查看共享内存属性

#include <sys/ipc.h>
#include <sys/shm.h>功能:用于控制共享内存
原型int shmctl(int shmid, int cmd, struct shmid_ds *buf);
参数shmid:由shmget返回的共享内存标识码cmd:将要采取的动作(有三个可取值)IPC_STAT:把shmid_ds结构中的数据设置为共享内存的当前关联值IPC_ET:在进程有足够权限的前提下,把共享内存的当前关联值设置为shmid_ds数据结构中给出的值IPC_RMID:删除共享内存段buf:指向一个保存着共享内存的模式状态和访问权限的数据结构//当cmd为IPC_RMID时,传NULL;当使用其他cmd时,传一个struct shmid_ds{}数据结构的指针进去,就能获得共享内存的信息(所有者、权限、大小、创建时间等信息)
返回值成功返回0;失败返回-1

注意:有进程和该块共享内存挂接时,nattch!=0,也可以完成删除操作,但是最好是先将进程去关联后再删除该块共享内存。

linux下是64位平台,无法把指针强转为int类型–8自己无法转4字节,可以把指针转成long long类型,并且给-1加上L

------ Shared Memory Segments --------
key        shmid      owner      perms      bytes      nattch     status      
0x66010309 3          yyq        600        4096       0                       ------ Shared Memory Segments --------
key        shmid      owner      perms      bytes      nattch     status      
0x66010309 3          yyq        600        4096       1                       //server先挂接上------ Shared Memory Segments --------
key        shmid      owner      perms      bytes      nattch     status      
0x66010309 3          yyq        600        4096       2                       //server和client都挂接上了------ Shared Memory Segments --------
key        shmid      owner      perms      bytes      nattch     status      
0x66010309 3          yyq        600        4096       1                       //client先去关联------ Shared Memory Segments --------
key        shmid      owner      perms      bytes      nattch     status      
0x66010309 3          yyq        600        4096       0                      //server回收资源

共享内存的数据结构如下

struct shmid_ds {struct ipc_perm shm_perm;    /* Ownership and permissions */ //centos用的名称是shm_permsize_t          shm_segsz;   /* Size of segment (bytes) */time_t          shm_atime;   /* Last attach time */time_t          shm_dtime;   /* Last detach time */time_t          shm_ctime;   /* Last change time */pid_t           shm_cpid;    /* PID of creator */pid_t           shm_lpid;    /* PID of last shmat(2)/shmdt(2) */shmatt_t        shm_nattch;  /* No. of current attaches */...};
struct ipc_perm { // struct shm_permkey_t          __key;    /* Key supplied to shmget(2) */uid_t          uid;      /* Effective UID of owner */gid_t          gid;      /* Effective GID of owner */uid_t          cuid;     /* Effective UID of creator */gid_t          cgid;     /* Effective GID of creator */unsigned short mode;     /* Permissions + SHM_DEST andSHM_LOCKED flags */unsigned short __seq;    /* Sequence number */};

查看共享内存属性

struct shmid_ds ds;
shmctl(shmid, IPC_STAT, &ds);
printf("%d-nattach:%d-key:%d\n", ds.shm_segsz, ds.shm_nattch, ds.shm_perm._key);

通信模块

用到的函数为

int snprintf(char *str, size_t size, const char *format, ...);

向特定的区域做格式化输入,共享内存没有输入输出接口,第一种方法:和以前一样定义一个缓冲区,然后把缓冲区的memcpy过去即可;第二种方法:共享内存和进程挂接上以后,shmat函数会直接给我们返回该段共享内存映射到进程地址空间的void*指针,直接把它强转为char*即可使用。

//方式1
const char* msg = "hello server, I'm client";
pid_t pid = getpid();
int count = 1;
char buffer[1024];
snprintf(buffer,sizeof(buffer), "%s[pid:%d][消息编号:%d]", msg, pid, count);
memcpy(start, buffer, strlen(buffer) + 1);
//方式2--挂接成功的返回值可以强转为char*,字符数组就可以直接用,不用缓冲区
const char* msg = "hello server, I'm client";
pid_t pid = getpid();
int count = 1;
snprintf(start, SHM_SIZE, "%s[pid:%d][消息编号:%d]", msg, pid, count++);

总结

共享内存段的优点

所有进程间通信方式中最快的一个方式,有效减少拷贝次数。==>不用缓冲区和memcpy

共享内存段的缺点

发消息的慢5s,读消息的快1s:读消息会一直读上一条的,等发过来了再读新的。即共享内存不会进行同步和互斥操作,没有对数据进行任何保护。类比管道,写端不写,读端就会阻塞等待;读端不读,写端写到缓冲区满了就不写了。需要使用信号量来对数据进行保护。

面试题:管道和共享内存

比较一下管道和共享内存(场景包括键盘输入和显示器输出),同样的代码,如果用管道/共享内存来实现,需要经过几次拷贝?

  • 管道:4次+2次
  • 共享内存:2次+2次

在这里插入图片描述

优化:共享内存的数据保护

需要实现类似于管道的功能,client写完了再通知server,进行读取,如果client没有写入或者没通知,server就不读取。

思路:同时使用匿名管道和共享内存,用匿名管道进行通知,共享内存传递消息。

相关文章:

systemV共享内存

systemV共享内存 共享内存区是最快的IPC形式。共享内存的大小一般是4KB的整数倍&#xff0c;因为系统分配共享内存是以4KB为单位的&#xff08;Page&#xff09;&#xff01;4KB也是划分内存块的基本单位。 之前学的管道&#xff0c;是通过文件系统来实现让不同的进程看到同一…...

Python基础之if逻辑判断

在学习if语句之前&#xff0c;我们先学习一种数据类型&#xff0c;布尔类型&#xff08;bool&#xff09;&#xff0c;在if语句中&#xff0c;我们需要通过判断条件是否为真或者假&#xff0c;才进入下面的语句块执行。 一、布尔类型&#xff08;bool&#xff09; 布尔类型&a…...

实现pdf文件预览

前言 工作上接到的一个任务&#xff0c;实现pdf的在线预览&#xff0c;其实uniapp中已经有对应的api&#xff1a;uni.openDocument(OBJECT)&#xff08;新开页面打开文档&#xff0c;支持格式&#xff1a;doc, xls, ppt, pdf, docx, xlsx, pptx。&#xff09;**实现了相关功能…...

【java】alibaba Fastjson --全解史上最快的JSON解析库

文章目录前序Fastjson 简介Fastjson 的优点速度快使用广泛测试完备使用简单功能完备下载和使用将 Java 对象转换为 JSON 格式JSONField创建 JSON 对象JSON 字符串转换为 Java 对象使用 ContextValueFilter 配置 JSON 转换使用 NameFilter 和 SerializeConfigFastjson 处理日期F…...

绝对零基础的C语言科班作业(期末模拟考试)(十道编程题)

编程题&#xff08;共10题&#xff1b; 共100.0分&#xff09;&#xff08;给猛男妙妙屋更一篇模拟考试&#xff09;模拟1&#xff08;输出m到n的素数&#xff09;从键盘输入两个整数[m,n], 输出m和n之间的所有素数。 输入样例&#xff1a;3&#xff0c;20输出样例&#xff1a;…...

按位与为零的三元组[掩码+异或的作用]

掩码异或的作用前言一、按位与为零的三元组二、统计分组1、map统计分组2、异或掩码总结参考资料前言 当a b 0时&#xff0c;我们能够很清楚的知道b是个什么值&#xff0c;b 0 - a -a&#xff0c;如果当a & b 0时&#xff0c;我们能够很清楚的知道b是什么值吗&#xf…...

C++基础篇(一)-- 简单入门

C 语言是在优化 C 语言的基础上为支持面向对象的程序设计而研制的一个通用目的的程序设计语言。在后来的持续研究中&#xff0c;C 增加了许多新概念&#xff0c;例如虚函数、重载、继承、标准模板库、异常处理、命名空间等。 C 语言的特点主要表现在两个方面&#xff1a;全面兼…...

前端整理 —— javascript 2

1. generator&#xff08;生成器&#xff09; 详细介绍 generator 介绍 generator 是 ES6 提供的一种异步编程解决方案&#xff0c;在语法上&#xff0c;可以把它理解为一个状态机&#xff0c;内部封装了多种状态。执行generator&#xff0c;会生成返回一个遍历器对象。返回的…...

Spring-注解注入

一、回顾XML注解 bean 配置 创建 bean public class Student { } 配置 xml bean <?xml version"1.0" encoding"UTF-8"?> <beans xmlns"http://www.springframework.org/schema/beans"xmlns:xsi"http://www.w3.org/2001/XMLSche…...

华为校招机试 - 攻城战(Java JS Python)

目录 题目描述 输入描述 输出描述 用例 题目解析 JavaScript算法源码 Java算法源码...

Docker入门

Docker一、何为DockerDocker是一个开源的应用容器引擎&#xff0c;基于GO语言并遵循从Apache2.0协议开源。Docker可以让开发者打包他们的应用以及依赖包到一个轻量级、可移植的容器中&#xff0c;然后在发布到任何流行的Linux机器上&#xff0c;也可以实现虚拟化。容器是完全使…...

时间序列分析 | CNN-LSTM卷积长短期记忆神经网络时间序列预测(Matlab完整程序)

时间序列分析 | CNN-LSTM卷积长短期记忆神经网络时间序列预测(Matlab完整程序) 目录 时间序列分析 | CNN-LSTM卷积长短期记忆神经网络时间序列预测(Matlab完整程序)预测结果模型输出基本介绍完整程序参考资料预测结果 模型输出 layers = 具有以下层的 151 Layer 数组:...

【蒸滴C】C语言结构体入门?看这一篇就够了

目录 一、结构体的定义 二、结构的声明 例子 三、 结构成员的类型 结构体变量的定义和初始化 1.声明类型的同时定义变量p1 2.直接定义结构体变量p2 3.初始化&#xff1a;定义变量的同时赋初值。 4.结构体变量的定义放在结构体的声明之后 5.结构体嵌套初始化 6.结构体…...

第十三届蓝桥杯

这里写目录标题一、刷题统计&#xff08;ceil函数返回的是等值于某最小整数的浮点值&#xff0c;不强制转换回int就wa&#xff0c;没错就连和int整数相加都wa二、修剪灌木&#xff08;主要应看清楚会调转方向三、统计子矩阵&#xff08;前缀和滑动窗口⭐&#xff09;四、[积木画…...

消息队列mq

应用场景&#xff1a; 1、解耦 2、削峰填谷 3、异步处理 4、消息通讯 工作模式&#xff1a; 一个消息只能被消费一次&#xff08;订阅模式除外&#xff09;&#xff0c;消费者接受到消息会回调业务逻辑&#xff0c;消费逻辑写在回调函数里面。 1、简单模式&#xff1a;一个生产…...

[学习笔记]黑马程序员Spark全套视频教程,4天spark3.2快速入门到精通,基于Python语言的spark教程

文章目录视频资料&#xff1a;一、Spark基础入门&#xff08;环境搭建、入门概念&#xff09;第二章&#xff1a;Spark环境搭建-Local2.1 课程服务器环境2.2 Local模式基本原理2.3 安装包下载2.4 Spark Local模式部署第三章&#xff1a;Spark环境搭建-StandAlone3.1 StandAlone…...

git push和 git pull的使用

git push与git pull是一对推送/拉取分支的git命令。git push 使用本地的对应分支来更新对应的远程分支。$ git push <远程主机名> <本地分支名>:<远程分支名>*注意: 命令中的本地分支是指将要被推送到远端的分支&#xff0c;而远程分支是指推送的目标分支&am…...

首发,pm3包,一个用于多组(3组)倾向评分匹配的R包

目前&#xff0c;本人写的第二个R包pm3包已经正式在CRAN上线&#xff0c;用于3组倾向评分匹配&#xff0c;只能3组不能多也不能少。 可以使用以下代码安装 install.packages("pm3")什么是倾向性评分匹配&#xff1f;倾向评分匹配&#xff08;Propensity Score Match…...

基于Canal的数据同步

基于Canal的数据同步 一、 系统结构 该数据同步系统由Spring Boot和Canal共同组成。 Spring Boot 是一个流行的 Java Web 框架&#xff0c;而 Canal 则是阿里巴巴开源的 MySQL 数据库的数据变更监听框架。结合 Spring Boot 和 Canal&#xff0c;可以实现 MySQL 数据库的实时数…...

vuetify设置页面默认主题色

前言 最近工作中接到一个任务&#xff1a; 项目中分light和dark两种主题色a、b页面默认为dark其他页面默认为light 项目前端环境&#xff1a; vue2jsyarnvuexvuetifyelement ui 解决思路 routerjs中配置路径时进行默认主题设置 在左侧aside点击菜单时&#xff0c;进行主题切…...

将嵌套循环中的Java对象数组转换为HashMap以优化性能

本文旨在指导开发人员如何通过将嵌套循环转换为Hashmap来优化Java代码的性能&#xff0c;特别是当涉及到对象属性的相等性检查时。通过使用Hashmap的快速搜索特性&#xff0c;可以显著降低时间复杂性&#xff0c;提高代码执行效率。本文将提供详细的步骤和示例代码&#xff0c;…...

ConvNeXt 改进 :ConvNeXt添加SAConv(可切换空洞卷积),自适应融合多尺度特征,优化小目标与遮挡目标感知,二次创新CNBlock结构

本文教的是方法,也给出几种改进方法,二次创新结构,百变不离其宗,一文带你改进自己模型,科研路上少走弯路。 作者提出的技术结合了递归特征金字塔和可切换空洞卷积,通过强化多尺度特征学习和自适应的空洞卷积,显著提升了目标检测的效果。 理论介绍 空洞卷积(Atrous Co…...

python基于微信小程序的旅游攻略分享平台

目录需求分析与功能规划技术架构设计数据库设计接口开发小程序前端开发部署与测试运营与迭代注意事项项目技术支持源码获取详细视频演示 &#xff1a;文章底部获取博主联系方式&#xff01;同行可合作需求分析与功能规划 明确平台核心功能&#xff1a;用户注册登录、攻略发布与…...

LabVIEW新手避坑指南:用For循环和数组搞定水仙花数,别再手动算啦!

LabVIEW实战&#xff1a;用For循环与数组高效求解水仙花数的5个关键技巧 水仙花数这个经典的编程练习题&#xff0c;在文本编程语言中可能只需十几行代码&#xff0c;但切换到LabVIEW的图形化编程环境时&#xff0c;不少初学者会陷入连线混乱和逻辑纠结。本文将从实际工程视角…...

七牛云图床避坑指南:如何避免CNAME解析和HTTPS配置中的常见错误

七牛云图床高阶配置实战&#xff1a;CNAME与HTTPS深度排错手册 第一次用七牛云图床时&#xff0c;我在凌晨三点对着屏幕上的404错误发呆——明明按照文档一步步操作&#xff0c;为什么图片死活加载不出来&#xff1f;后来才发现是CNAME解析的TTL缓存问题。这种看似简单的配置背…...

vLLM-v0.17.1实操手册:SSH环境下vLLM服务日志实时分析与性能诊断

vLLM-v0.17.1实操手册&#xff1a;SSH环境下vLLM服务日志实时分析与性能诊断 1. vLLM框架简介 vLLM是一个专注于大语言模型(LLM)推理和服务的高性能开源库&#xff0c;由加州大学伯克利分校的天空计算实验室(Sky Computing Lab)发起&#xff0c;现已发展为社区驱动的项目。它…...

SIM800L新手避坑指南:从电源不稳到中文短信发送,我的踩坑实录

SIM800L实战避坑手册&#xff1a;从电源设计到中文短信的完整解决方案 第一次拿到SIM800L模块时&#xff0c;我天真地以为这不过是个"高级版蓝牙模块"。直到电源指示灯开始疯狂闪烁、串口不断吐出乱码、中文短信变成问号时&#xff0c;我才意识到自己掉进了技术深坑。…...

AI原生应用的微服务架构设计模式

AI原生应用的微服务架构设计模式&#xff1a;用智能餐厅的故事讲透AI与微服务的碰撞关键词&#xff1a;AI原生应用、微服务架构、设计模式、模型生命周期、实时数据流摘要&#xff1a;当AI大模型、边缘计算和实时决策需求爆发时&#xff0c;传统单体架构已无法满足AI应用的动态…...

OpenClaw安全加固:Qwen3.5-9B操作权限的4层防护

OpenClaw安全加固&#xff1a;Qwen3.5-9B操作权限的4层防护 1. 为什么需要安全加固&#xff1f; 上周我在用OpenClaw自动处理一份包含客户联系方式的Excel表格时&#xff0c;突然意识到一个问题&#xff1a;如果AI助手误操作删除了关键文件怎么办&#xff1f;更可怕的是&…...

OpenClaw成本优化方案:ollama GLM-4.7-Flash自建模型接口实践

OpenClaw成本优化方案&#xff1a;ollama GLM-4.7-Flash自建模型接口实践 1. 为什么需要关注OpenClaw的token消耗问题 第一次用OpenClaw完成自动化周报任务时&#xff0c;我盯着账单倒吸一口凉气——生成三份周报竟然消耗了接近15万token。这让我意识到&#xff0c;如果不解决…...