systemV共享内存

news2025/1/19 8:21:20

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_perm
               size_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_perm
               key_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 and
                                           SHM_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就不读取。

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

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

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

相关文章

通用SQL查询分析器

技术&#xff1a;Java、JSP等摘要&#xff1a;本文主要针对当前很多软件都无法实现跨数据库、跨平台来执行sql语句而用户又仅需做一些基本的增删改查操作的矛盾&#xff0c;设计了一个能够跨平台跨数据库的软件。此软件是一个通用SQL查询分析器&#xff0c;利用java语言本身的跨…

rust中如何利用generic与PhantomData来实现更清晰的接口

前两天看了一个在 rustlang 中如何利用 generic 和 PhantomData 来让我们的 api 更加合理的视频&#xff0c; 当时看完就想写一篇相关内容的文章&#xff0c; 但是没有立即动手&#xff0c;一推迟&#xff0c;不出意外的忘了。这两天又接手了一个半成品的项目&#xff0c; 需要…

C++程序调用IsBadReadPtr或IsBadWritePtr引发内存访问违例问题的排查

目录 1、问题描述 2、VS中看不到有效的信息&#xff0c;尝试使用Windbg去分析 3、使用Windbg分析 4、最后 VC常用功能开发汇总&#xff08;专栏文章列表&#xff0c;欢迎订阅&#xff0c;持续更新...&#xff09;https://blog.csdn.net/chenlycly/article/details/12427258…

数据结构-链表-单链表(3)

目录 1. 顺序表的缺陷 2. 单链表 2.1 单链表的基本结构与接口函数 2.2 重要接口 创建新节点的函数&#xff1a; 2.2.1 尾插 2.2.2 头插 2.2.3 尾删 2.2.4 头删 2.2.5 查找 2.2.6 插入 2.2.7 删除 2.2.8 从pos后面插入 2.2.9 从pos后面删除 3. 链表的缺陷与优势&…

传输数据格式:JSON 异步加载

JSON JSON是一种传输数据的格式&#xff08;以对象为样板&#xff0c;本质上就是对象&#xff0c;但用途有区别&#xff0c;对象就是本地用的&#xff0c;json是用来传输的&#xff09;JSON.parse();string --> jsonJSON.stringify();json --> string json ---> {n…

关于安卓的一些残缺笔记

安卓笔记Android应用项目的开发过程Android的调试Android项目文档结构Intent的显式/隐式调用Activity的生命周期1个Activity界面涉及到生命周期的情况2个Activity界面涉及到生命周期的情况Android布局的理论讲解Activity界面布局ContentProvider是如何实现数据共享Android整体架…

mysql视图和存储过程

视图视图就是将一条sql查询语句封装起来&#xff0c;之后使用sql时&#xff0c;只需要查询视图即可&#xff0c;查询视图时会将这条sql语句再次执行一遍。视图不保存数据&#xff0c;数据还是在表中。SELECT 语句所查询的表称为视图的基表&#xff0c;而查询的结果集称为虚拟表…

ATTCK v10版本战术实战研究—持久化(一)

一、前言“在网络安全的世界里&#xff0c;白帽子与黑帽子之间无时无刻都在进行着正与邪的对抗&#xff0c;似乎永无休止。正所谓&#xff0c;道高一尺魔高一丈&#xff0c;巨大的利益驱使着个人或组织利用技术进行不法行为&#xff0c;花样层出不穷&#xff0c;令人防不胜防。…

udk2017环境搭建编译步骤

win10 64bit系统 1.参考minnowboard-max-rel-1-01-bin-releasenotes-for-binary-firmware-images.TXT MyWorkspace.rar 解压到c:\&#xff0c;参考txt中的git操作 3.复制ASL,NASM 到c&#xff1a;\ 安装vs2015 &#xff0c;勾选sdk 5.安装 python-2.7.10.amd64.msi&#xf…

【论文泛读】NeRF: Representing Scenes as Neural Radiance Fields for View Synthesis

NeRF: Representing Scenes as Neural Radiance Fields for View Synthesis | NeRF: 用于视图合成的神经辐射场的场景表示 | 2020年 出自文献&#xff1a;Mildenhall B, Srinivasan P P, Tancik M, et al. Nerf: Representing scenes as neural radiance fields for view synth…

泼辣修图Polarr5.11.4 版,让你的创意无限延伸

泼辣修图是一款非常实用的图片处理软件&#xff0c;它不仅拥有丰富的图片处理功能&#xff0c;而且还能够轻松地实现自定义操作。泼辣修图的操作界面非常简洁&#xff0c;功能也非常丰富&#xff0c;使用起来非常方便快捷。 泼辣修图拥有非常丰富的图片处理功能&#xff0c;包括…

【冲刺蓝桥杯的最后30天】day1

大家好&#x1f603;&#xff0c;我是想要慢慢变得优秀的向阳&#x1f31e;同学&#x1f468;‍&#x1f4bb;&#xff0c;断更了整整一年&#xff0c;又开始恢复CSDN更新&#xff0c;从今天开始逐渐恢复更新状态&#xff0c;正在备战蓝桥杯的小伙伴可以支持一下哦&#xff01;…

Rockchip Android13 GKI开发指南

Rockchip Android13 GKI开发指南 文章目录Rockchip Android13 GKI开发指南GKI介绍Google upstream kernel下载及编译Rockchip SDK中GKI相关目录介绍Rockchip GKI编译代码修改编译固件烧写KO编译及修改添加新的模块驱动的方法调试ko方法开机log确认uboot阶段Android阶段KO加载KO…

Java IO流详解

文章目录一、File1.1 构造方法1.2 文件操作 方法1.3 目录操作 方法1.4 文件检测 方法1.5 获取文件信息 方法1.6 应用练习二、IO 流2.1 InputStream 字节输入流 (读)&#x1f353;FileInputStream&#x1f353;BufferedInputStream2.2 OutputStream 字节输出流 (写)&#x1f34c…

【Redis】redis大key和大value的危害,如何处理?

前序 还记得上次和同事一起去面试候选人时&#xff0c;同事提了一个问题&#xff1a;Redis的大key有什么危害&#xff1f;当时候选人主要作答的角度是一个key的value较大时的情况&#xff0c;比如&#xff1a; 内存不均&#xff1a;单value较大时&#xff0c;可能会导致节点之…

[经验分享]gpt-3.5-Turbo|unity中实现http接口调用gpt新接口以及信息处理的实现案例分享

最近openAI发布了目前chatGPT所使用的模型gpt-3.5-Turbo&#xff0c;之前使用了text-davinci-003模型做了一个galgame的AI女友对话的demo。这次趁着新接口的发布&#xff0c;对这个demo也同步更新了模型调用的代码。本篇文章将分享一下&#xff0c;如何在unity里使用UnityWebRe…

记录一次PWM信号异常问题

问题我使用单片机输出PWM控制机械臂&#xff0c;但是控制过程中&#xff0c;机械臂总是会出现莫名的抽动。利用示波器测试PWM信号&#xff0c;发现信号正常。过程&#xff08;1&#xff09;在反复的测试过程中&#xff0c;队友提出&#xff0c;将示波器的地线放在左侧的GND波形…

计算机EI会议论文,和EI期刊论文有什么区别? - 易智编译EaseEditing

EI期刊论文&#xff0c;是期刊论文的一种。顾名思义&#xff0c;就是指发在期刊上的论文。 期刊论文发表的格式需要具体参考各期刊文章的要求学术论文格式&#xff0c;主要会发在月刊/季刊/年刊/不定期的刊上。 目前&#xff0c;国际著名的科技文献检索系统是SCI&#xff08;…

安卓-AndroidManifest.xml修复

解析编译之后的AndroidManifest文件格式&#xff1a;http://www.520monkey.com/archives/575 案例apk jadx打开发现AndroidManifest.xml异常&#xff0c;无法正常显示 那么我们用apktool反编译试试 apktool d APK逆向-2.apk -f可以看到报错了&#xff0c;显示不能解析此xml…

[SSD科普] 固态硬盘物理接口SATA、M.2、PCIe常见疑问,如何选择?

前言犹记得当年Windows 7系统体验指数中&#xff0c;那5.9分磁盘分数&#xff0c;在其余四项的7.9分面前&#xff0c;似乎已经告诉我们机械硬盘注定被时代淘汰。势如破竹的SSD固态硬盘&#xff0c;彻底打破了温彻斯特结构的机械硬盘多年来在电脑硬件领域的统治。SSD数倍于HDD机…