Linux 进程间通信——共享内存

news2025/1/10 16:27:18

一、共享内存原理

共享内存为多个进程之间共享和传递数据提供了一种有效的方式。共享内存是先在物理内存上申请一块空间,多个进程可以将其映射到自己的虚拟地址空间中。所有进程都可以访问共享内存中的地址,就好像它们是由malloc分配的一样。如果某个进程向共享内存写入了数据,所做的改动将立刻被可以访问同一段共享内存的任何其他进程看到。由于它并未提供同步机制,所以我们通常需要用其他的机制来同步对共享内存的访问。

在这里插入图片描述
如果将一块物理内存分配给了A进程,那么就不能再把它分配给B进程了。但是对于共享内存来说是可以的,可以把一块共享内存既映射到A进程的虚拟地址空间中,也可以把它映射到B进程的虚拟地址空间中,也就是说进程A和进程B的逻辑内存中实际底层对应的物理内存有一部分是重叠的,进程A和进程B共同使用这同一块物理内存。

【注意】

共享内存和管道的区别:

对于管道来说,首先要有一个进程把数据写到管道中,然后另一个进程再从管道中将数据读出来,相当于一个进程把数据复制到管道中,另一个进程又将数据从管道中复制出来。对于共享内存,两个或者多个进程用的是同一块物理空间,数据放到共享内存中,每一个进程可以直接将数据写入共享内存或者直接读取共享内存中的数据,只要有一个进程将数据写入了共享内存,这个进程和其他进程都可以访问这些数据。

二、共享内存的使用

1.操作共享内存的接口介绍

(1)shmget()创建共享内存

int shmget(key_t key, size_t size, int shmflg);  

shmget()用于创建或者获取共享内存
shmget()成功返回共享内存的ID, 失败返回-1
key:不同的进程使用相同的key值可以获取到同一个共享内存
size:创建共享内存时,指定要申请的共享内存空间大小
shmflg: 如果是创建新的共享内存需要使用IPC_CREAT,IPC_EXCL;如果是已经存在的可以使用IPC_EXCL或者直接传0。

(2)shmat()映射共享内存

 void* shmat(int shmid, const void *shmaddr, int shmflg); 

shmat()将申请的共享内存的物理内存映射到当前进程的虚拟地址空间上
shmat()成功返回返回共享内存的首地址,失败返回NULL
shmid:共享内存标识符
shmaddr:shmaddr=0,则存储段连接到由内核选择的第一个可用地址上。所以一般给NULL,由系统自动选择映射的虚拟地址空间 。
shmflg: 一般给0, 可以给SHM_RDONLY为只读模式,其他的为读写 。

(3)shmdt()断开共享内存

当进程间完成通信时,就需要去关联共享内存,需要将进程从之前映射的共享内存上脱离下来。

int shmdt(const void *shmaddr);  

shmdt()断开当前进程的shmaddr指向的共享内存映射
shmdt()成功返回0, 失败返回-1

(4)shmctl()释放共享内存

当结构体中shm_nattch为0时就需要释放这块共享内存,否则就会一直占用下去,因为共享内存的生命周期是跟随内核的。

int shmctl(int shmid, int cmd, struct shmid_ds *buf);

shmctl()控制共享内存
shmctl()成功返回0,失败返回-1
shmid:共享内存标识符
cmd:指定执行的操作,设置为 IPC_RMID 时表示释放共享内存
buf:设置为空就行

2.使用共享内存

(1)进程a向共享内存中写入数据,进程b从共享内存中读取数据并显示

a.c代码:

在这里插入图片描述

b.c代码:

在这里插入图片描述

运行结果:

在这里插入图片描述

(2)进程a从键盘循环获取数据并写入到共享内存中,进程b从共享内存中获取并打印数据。要求进程a输入一次,进程b输出一次,进程a不输入,进程b也不输出。

a.c代码:

在这里插入图片描述

运行结果:

在这里插入图片描述

由结果可以看出,进程a循环向共享内存中写入数据之后,进程b就会循环且不停地从共享内存中读取数据。

要做到进程a输入一次,进程b输出一次,进程a不输入,进程b也不输出,就要将信号量引入,通过p、v操作解决这个问题。

【分析】需要创建两个信号量,第一个信号量的初始值为1,第二个信号量的初始值为0。在a程序执行向共享内存中写入数据之前执行第一个信号量的p操作,第一个信号量的值变为了0,在a程序执行完向共享内存中写入数据之后执行第二个信号量的v操作,第二个信号量的值变为了1,在b程序执行向共享内存中读取数据之前执行第二个信号量的p操作,第二个信号量的值变为0,在b程序执行完向共享内存中读取数据之后执行第一个信号量的v操作,第一个信号量的值变为1。

也就是说,现在如果先执行b程序,此时因为第二个信号量的初始值为0,执行不了p操作,就会发生阻塞。接着执行a程序,因为第一个信号量的初始值为1,执行p操作成功,第一个信号量的值变为0,然后写入数据到共享内存成功,执行第二个信号量的v操作,因为第二个信号量的初始值为0,执行完v操作之后变为1,这时b程序就可以执行对第二个信号量的p操作,执行成功,第二个信号量的值又变为0,b程序读取共享内存的数据成功,然后执行对第一个信号量的v操作,第一个信号量变为1。就这样通过信号量的p、v操作一直循环写入和读取,就实现了a进程输入一次,b进程读取一次,a进程不输入,b进程也不输出。

信号量接口的实现:

sem.h代码:

在这里插入图片描述

sem.c代码:

在这里插入图片描述

在这里插入图片描述

a.c代码:

在这里插入图片描述

b.c代码:

在这里插入图片描述

运行结果:

在这里插入图片描述

三、查看共享内存的信息

在命令行通过ipcs -m查看共享内存的信息:

在这里插入图片描述
在运行a程序之后,可以看到此时共享内存被创建,且连接数有1个。

结束a进程之后,共享内存仍然存在,但是连接数变为了0:

在这里插入图片描述
通过命令行释放该共享内存:

方法:

ipcrm -m 1             # ipcrm -m 共享内存的id

结果:

在这里插入图片描述

【总结】

(1)共享内存允许两个不相关的进程访问同一个逻辑内存。共享内存是在两个正在运行的进程之间传递数据的一种非常有效的方式。大多数共享内存的具体实现,都把由不同进程之间共享的内存安排为同一段物理内存。

(2)共享内存是由进程间通信创建的一个特殊的地址范围,它将出现在该进程的地址空间中。其他进程可以将同一段共享内存连接到它们自己的地址空间中。所有进程都可以访问共享内存中的地址。如果某个进程向共享内存写入了数据,所做的改动将立刻被可以访问同一段共享内存的任何进程看到。

(3)共享内存为在多个进程之间共享和传递数据提供了一种有效的方式。

(4)共享内存并没有提供同步机制,通常需要其他的机制来同步对共享内存的访问。一般用共享内存来提供对大块内存区域的有效访问,同时通过传递小消息来同步对该内存的访问。

(5)在第一个进程结束对共享内存的写操作之前,并没有自动的机制可以阻止第二个进程开始对它进行读取。对共享内存访问的同步控制必须由程序员来负责。

(6)共享内存的生命周期是跟随内核的,进程退出后,共享内存依然存在,共享内存不属于任何进程,不归进程管理,除非调用释放函数,否则要不要释放是OS决定的,因此共享内存的生命周期是随内核的,所以如果不调用释放函数释放这块共享内存,否则就会一直占用下去。释放共享内存的方式有三种,分别是关机、调用释放共享内存的函数 shmctl和命令行释放,命令行释放的方法:

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

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

相关文章

实现一个自动保存高CPU占用现场的简易工具

CPU 使用率在系统监控中是一个非常重要的指标。对于大多数 Web 应用来说,它们往往是 IO 密集型的,因此只会在某些时刻可能会出现 CPU 突然飙升的情况,随后很快就恢复正常。然而,当收到报警并想要排查问题时,CPU 飙升的…

Windows10上VS2022单步调试FFmpeg 4.2源码

之前在 https://blog.csdn.net/fengbingchun/article/details/103735560 介绍过通过VS2017单步调试FFmpeg源码的方法,这里在Windows10上通过VS2022单步调试FFmpeg 4.2的方法:基于GitHub上ShiftMediaProject/FFmpeg项目,下面对编译过程进行说明…

VS2022远程Linux使用cmake开发c++工程配置方法

文章目录 远程连接CMakePresets.json的配置Task.vs.json配置launch.vs.json配置最近使用别人在VS2015上使用visualgdb搭建的linux开发环境,各种不顺手,一会代码不能调转了,一会行号没了,调试的时候断不到正确的位置,取消的断点仍然会进。因此重新摸索了一套使用vs的远程开…

合并多个文本文件

使用 wxPython 模块合并多个文本文件的博客。以下是一篇示例博客: C:\pythoncode\blog\txtmerge.py 在 Python 编程中,我们经常需要处理文本文件。有时候,我们可能需要将多个文本文件合并成一个文件,以便进行进一步的处理或分析。…

MySQL的配置文件my.cnf与my.ini

一、my.cnf与my.ini win系统,MySQL配置文件为my.ini 其他系统(Ubuntu、CentOS、macOS)MySQL配置文件为my.cnf 二、my.cnf与my.ini的路径 2.1 默认路径 MySQL 的配置文件 my.cnf 可能位于多个位置,具体取决于安装方式和操作系统。以下是一…

《HeadFirst设计模式(第二版)》第十章代码——状态模式

如下图所示,这是一个糖果机的状态机图,要求使用代码实现: 初始版本: package Chapter10_StatePattern.Origin;/*** Author 竹心* Date 2023/8/19**/public class GumballMachine {final static int SOLD_OUT 0;final static int…

【编织时空四:探究顺序表与链表的数据之旅】

本章重点 链表的分类 带头双向循环链表接口实现 顺序表和链表的区别 缓存利用率参考存储体系结构 以及 局部原理性。 一、链表的分类 实际中链表的结构非常多样,以下情况组合起来就有8种链表结构: 1. 单向或者双向 2. 带头或者不带头 3. 循环或者非…

【论文解读】Observation-Centric SORT:Rethinking SORT for Robust Multi-Object Tracking

一.介绍 1.1 之前卡尔曼方法存在的问题: 1.长时间的运动的线性估计可能是非常不准确的。2.当没有可用于更新卡尔曼滤波器参数的测量时,标准惯例是信任先验状态估计进行后验更新,这导致了在一段时间内错误的积累。 1.2 基于假设 假设跟踪目…

ARM体系结构学习笔记:位操作和灵活的2nd操作数

位操作 移位运算 数据传输指令 灵活的2nd操作数 Set a bit a | (1 << 5)Clear a bit a & ~(1 << 5)Toggling a bt a ^ 1<<5

IDEA开发项目时一直出现http404错误的解决方法

系列文章目录 安装cv2库时出现错误的一般解决方法_cv2库安装失败 SQL&#xff1e; conn sys/root as sysdbaERROR:ORA-12560: TNS: 协议适配器错误的解决方案 虚拟机启动时出现“已启用侧通道缓解”的解决方法 Hypervisor launch failed&#xff1b; Processor does not pr…

数据的绘画工场:Python绘图库Pyecharts,打造引人入胜的可视化效果

欢迎阅读本篇文章&#xff0c;本文将带您从零开始&#xff0c;逐步掌握使用Pyecharts库进行数据可视化的技能。Pyecharts是一个基于Echarts的Python可视化库&#xff0c;能够轻松创建各种交互式图表和地图&#xff0c;无论您是数据分析新手还是有经验的开发者&#xff0c;本文都…

【计算机视觉】相机基本知识(还在更新)

1.面阵工业相机与线阵工业相机 1.1 基本概念区别 面阵相机则主要采用的连续的、面状扫描光线来实现产品的检测&#xff1b; 线阵相机即利用单束扫描光来进行物体扫描的工作的。 1.2 优缺点 &#xff08;1&#xff09;面阵CCD工业相机&#xff1a; 优点&#xff1a;应用面…

ZooKeeper集群服务器启动

在本文中&#xff0c;我们将对集群版ZooKeeper服务器的启动过程做详细讲解。集群和单机ZooKeeper服务器的启动过程在很多地方都是一致的&#xff0c;因此本节只会对有差异的地方展开进行讲解。下图所示是集群版ZooKeeper服务器的启动流程图。 预启动 预启动的步骤如下。 (1)统…

财报解读:上半年业绩实现增长,药师帮业务飞轮已经开始旋转?

今年6月底登陆港股的药师帮&#xff0c;近日发布了上市后的首份财务报告。 财报显示&#xff0c;2023年上半年&#xff0c;药师帮实现营收增长、经调整后净利润转正的成果&#xff0c;再次验证了二级市场对于其发展潜力的看好——6月底上市以来&#xff0c;药师帮股价涨幅接近…

Mybatis的学习笔记(IDEA快捷键,参数占位符,转义符)

一、IDEA快捷键&#xff1a; IDEA多行注释&#xff1a;ctrlShift/ 单行注释&#xff1a;ctrl/ 导入包&#xff0c;自动修正代码&#xff1a;altenter 自动生成代码&#xff1a;altinsert 二、Mybatis重要知识点&#xff1a; 2.1 参数占位符 一共分为2种&#xff1a;#{}和…

idea2023 springboot+mybatis+jsp 初学单表增删改查

创建项目 因为2.7.14使用量较少&#xff0c;特更改spring-boot为2.7.5版本 配置端口号 打开Sm01Application类&#xff0c;右键运行启动项目&#xff0c;或者按照如下箭头启动 启动后&#xff0c;控制台提示如下信息表示成功 此刻在浏览器中输入&#xff1a;http://lo…

盘点市面上的ipad协议对比

友情链接 geweapi.com 点击即可访问! Web网页端&#xff1a;2017年后不再支持新号登录&#xff0c;仅支持老号&#xff0c;并且掉线严重&#xff0c;功能缺失严重。 Xposed技术&#xff1a;在2019年6月份&#xff0c;微信官方在行业重点打击Xposed&#xff0c;自此行业内一片…

企望制造ERP系统 RCE漏洞[2023-HW]

企望制造ERP系统 RCE漏洞 一、 产品简介二、 漏洞概述三、 复现环境四、 漏洞复现小龙POC检测 五、 修复建议 免责声明&#xff1a;请勿利用文章内的相关技术从事非法测试&#xff0c;由于传播、利用此文所提供的信息或者工具而造成的任何直接或者间接的后果及损失&#xff0c;…

IO day 4

1、使用两个进程完成两个文件的拷贝&#xff0c;父进程拷贝前一半内容&#xff0c;子进程拷贝后一半内容&#xff0c;并且父进程要阻塞回收子进程资源 #include <myhead.h>int main(int argc, const char *argv[]) {char a[1] {0};pid_t pid;pid fork();//创建一个子进…

马哈鱼数据血缘工具背后的项目: gsp_demo_java 项目简单介绍与使用

0.背景 马哈鱼数据血缘工具(https://www.sqlflow.cn/)是SQLflow工具的中文译名,实际就是sqlflow. 对于SQL flow来说,底层调用的是General SQL Parser(GSP https://sqlparser.com) 的库. 这个gsp有开源的java demo项目:https://github.com/sqlparser/gsp_demo_java 1.快速使用…