进程间通信 ---共享内存

news2024/12/29 9:34:46

序言

 在前一篇文章中,我们介绍了名为 👉管道 的进程间通信的方式,该种方式又可分为 匿名管带,命名管道。前者最大的特点就是 仅支持包含血缘关系两进程之间的通信,而后者 支持任意进程间的通信
 在本篇文章中,我们将介绍一种新的进程间通信方式 共享内存,它允许多个进程或线程访问同一块内存区域,以实现数据的高效共享和同步。


1. 共享内存的原理

 我们在之前提到一个概念就是 让不同的进程看到同一份操作系统的资源(如文件,内存等),共享内存无非就是让不同的进程看到内存中的同一块内存区域。但是具体的细节是怎么样的呢?请看图:

在这里插入图片描述
现在我们看图说话,描述怎么实现使用共享内存进行通信:

  1. 申请空间:需要向操作系统申请在内存上的一块指定大小的空间。
  2. 内存映射:虽然申请到了空间,但是该空间并不能为进程所用,因为进程地址空间上实际并未拿到那块空间,所以需要 使用页表建立映射关系,将该地址的虚拟地址存储到进程地址空间的共享区中。
  3. 数据访问:程序可以通过指针来写入或读取这些内存的数据。
  4. 释放空间:当我们结束通信时,一定要释放申请的空间。但是管道都不需要手动释放呀,为什么共享内存需要呢?因为 管道的生命周期随进程,而共享内存的生命周期随系统

2. 相关的指令和函数

环境:Linux 操作系统

2.1 指令:ipcs -m

 通过该指令我们可以用于显示当前系统中的共享内存段的信息:
在这里插入图片描述
当前我们系统下就存在三个共享存储段。

2.2 指令:ipcs -m [shmid]

 通过该指令可以删除指定的共享内存段。
注意:使用 shmid,而不是 key!!!

2.3 函数:shmget

 该函数用于创建或者是获取共享内存段的系统调用函数:
int shmget(key_t key, size_t size, int shmflg);

  • key:共享内存的键值(key)。这是一个用于 标识共享内存段的唯一标识符
  • size:共享内存段的大小(以字节为单位)。这个值必须大于 0,并且需要是系统页面大小的整数倍(尽管大多数系统允许自动向上舍入到最近的页面大小)。
  • shmflg:模式标志和权限。这个参数是一个位掩码,可以组合多个标志位和权限位。
  • 返回值:成功时,返回共享内存段的标识符(一个非负整数)。这个标识符是后续 对共享内存段进行操作的唯一标识。

在这里我们好好聊聊其中几个大家可能有疑惑的参数:

 首先是 key返回值
为什么我们需要指定 key 呢?我反问大家一个问题,两个进程要使用共享内存通信,但两个进程怎么获取同一块内存空间呢?举个栗子:操作系统给我们分配内存空间就像给我们建立一个房子,现在有多少个进程之间需要通信,那操作系统就分配多少个房间,那怎么知道哪间房间是谁的呢?进程为自己房间都装一个门牌号!而 key 就是门牌号的内容。
那返回值呢,又是干嘛的呢?操作系统把门牌号给你装好了,返回值就是给你配的房卡,你不用记住门牌号,用房卡就行。

 其次就是 shmflg:
常见的标志位包括 IPC_CREAT(如果共享内存不存在,则创建它)和 IPC_EXCL(与 IPC_CREAT 一起使用,确保创建的共享内存是新的,如果已存在则返回错误)。权限位(如 0666 )指定了共享内存的访问权限,这些权限将和进程的umask值进行逻辑与操作来确定最终的权限,
 所以一般情况下,你需要创建一个共享内存,那你的标志位就是 IPC_CREAT | IPC_EXCL | 0666
需要获取一个共享内存,标志位是:IPC_CREAT | 0666

2.4 函数:ftok

 我们需要对 shmget 函数传入一个唯一的 key (不能和其它进程起冲突) ,我们可以直接使用这个函数为我们生成:
key_t ftok(const char *pathname, int proj_id);

  • pathname:指向文件路径的指针,这个文件通常是项目中的一个已知文件或目录。虽然文件路径不需要指向一个实际存在的文件,但必须是唯一的,以便在不同的项目或实例中生成不同的键。
  • proj_id:一个 8 位( 1 字节)的整数,通常用于进一步区分同一路径下的不同键。尽管 proj_idint 类型,但实际上只使用其低 8 位(即0-255的范围)。
  • 返回值:如果成功,ftok 函数返回一个唯一的键( key_t 类型)。失败返回 -1 。

2.5 函数:shmat

 在原理中,我们说到,我们需要将操作系统为我们申请的空间映射到进程的进程地址空间上,这个函数 void *shmat(int shmid, const void *shmaddr, int shmflg); 就是实现这一功能的函数:

  • shmid:共享内存标识符,由 shmget 函数返回。

  • shmaddr:指定共享内存出现在进程内存地址的什么位置。如果直接指定为 NULL,则让内核自己决定一个合适的地址位置。

  • shmflg:标志位,通常使用SHM_RDONLY表示以只读模式映射共享内存,否则为读写模式。
    注意:一般没什么特殊需求后两位都使用默认

  • 返回值: 成功时,返回映射的共享内存区域的 起始地址;出错时,返回 (void *)-1,并将错误原因存储在 errno 中。

大家可能对 void * 指针有些疑惑,这类指针就是不指向任何类型的指针,就像一张白纸,你需要告诉他,他具体操作的数据。(malloc 函数的返回的也是 void 指针,需要强转为你需要的指针

2.6 函数:shmdt

 这个函数的作用是 分离共享内存段,请注意!这不是释放共享内存,相当于只是解除了映射关系,但是该共享内存还存在!int shmdt(const void *shmaddr);

  • shmaddr:这是一个指向先前由 shmat 调用返回的共享内存段的指针。它指定了要分离的共享内存段的起始地址。
  • 返回值: 成功时,返回 0;出错时,返回 -1,并设置 errno 以指示错误类型。

2.7 函数:shmctl

 该函数不仅可以释放共享内存,还可以查询共享内存的状态、修改其属性,
int shmctl(int shmid, int cmd, struct shmid_ds *buf);

  • shmid:共享内存标识符,即要控制的共享内存段的标识符。
  • cmd:控制命令,用于指定要执行的操作。常用的命令包括:
     1. IPC_STAT:获取共享内存的状态,将共享内存的 shmid_ds 结构复制到 buf 中。
     2.IPC_SET:改变共享内存的状态,将 buf 所指的 shmid_ds 结构中的 uid、gid、mode 等成员复制到共享内存的 shmid_ds 结构内。
     3.IPC_RMID:删除共享内存段。注意,删除利用了引用计数,当所有进程都进行删除后,才会真正删除。
  • buf:指向 struct shmid_ds 结构的指针。
  • 返回值:成功时,返回 0‘出错时,返回 -1,并设置 errno 以指示具体的错误原因。

在这里如果我们想要删除:
shmctl(shmid, IPC_RMID, NULL)

如果我们想要获取相应信息:

struct shmid_ds shmbuf;  
shmctl(shmid, IPC_STAT, &shmbuf);

修改信息使用的很少,在这里就不介绍了。


3. 总结

 在这篇文章中向大家介绍了共享内存的原理以及常用的指令函数,希望大家有所收获!😁

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

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

相关文章

python3.9+wxPython设计的一个简单的计算器

运行环境:python3.9wxPython4.2.1 运行效果: 按下等于号,输出: 按下R键,保留两位小数 键盘布局与逻辑分离,添加删除功能一般功能或修改键盘布局只需要更改词典的顺序即可。添加特殊功能时则需要将队对应的…

【kubernetes】k8s配置资源管理

一、ConfigMap资源配置 ConfigMap保存的是不需要加密配置的信息 ConfigMap 功能在 Kubernetes1.2 版本中引入,许多应用程序会从配置文件、命令行参数或环境变量中读取配置信息。ConfigMap API 给我们提供了向容器中注入配置信息的机制,ConfigMap 可以被…

基于vue框架的CKD电子病历系统nfa2e(程序+源码+数据库+调试部署+开发环境)系统界面在最后面。

系统程序文件列表 项目功能:患者,医生,药品信息,电子病历,临时医嘱,长期医嘱,健康科普 开题报告内容 基于Vue框架的CKD电子病历系统 开题报告 一、选题背景 随着信息技术的飞速发展和医疗信息化的深入推进,电子病历系统(Electronic Medic…

SpringBoot事务-调度-缓存

一.Spring Boot中的事务管理 设置事务 Transactional(isolation Isolation.DEFAULT) Transactional(propagation Propagation.REQUIRED) 开启事务 EnableTransactionManagement ​​​​​​​ 1. 开启事务管理 要开启 Spring 的事务管理,你需要在你的 Spring B…

Docker 日志管理

一、ELK -Filebeat Elasticsearch 数据的存储和检索 常用端口: 9100:elasticsearch-head提供web访问 9200:elasticsearch与其他程序连接或发送消息 9300:elasticsearch集群状态 Logstash 有三个组件构成input,fi…

网安行业薪资:「3人拿4干5」

吉祥知识星球http://mp.weixin.qq.com/s?__bizMzkwNjY1Mzc0Nw&mid2247485367&idx1&sn837891059c360ad60db7e9ac980a3321&chksmc0e47eebf793f7fdb8fcd7eed8ce29160cf79ba303b59858ba3a6660c6dac536774afb2a6330#rd 《网安面试指南》http://mp.weixin.qq.com/s…

计算机毕业设计 农家乐管理平台 Java+SpringBoot+Vue 前后端分离 文档报告 代码讲解 安装调试

🍊作者:计算机编程-吉哥 🍊简介:专业从事JavaWeb程序开发,微信小程序开发,定制化项目、 源码、代码讲解、文档撰写、ppt制作。做自己喜欢的事,生活就是快乐的。 🍊心愿:点…

Linux | Linux开发工具链全攻略:yum、vim、gcc/g++、GDB、Makefile与git版本控制

目录 Linux开发环境全解析:工具、编程与版本控制 1、软件包管理器YUM 查看可用的软件包 安装软件包 更新软件包 卸载软件包 查找软件包信息 清理缓存 检查可更新的软件包 显示软件包的依赖关系 2、Vim编辑器 vim的三种模式:命令模式、插入模…

计算机基础知识复习8.13

cookie和session区别 cookie:是服务器发送到浏览器,并保存在浏览器端的一小块数据 浏览器下次访问服务时,会自动携带该块数据,将其发送给服务器 session:是javaEE标准,用于在服务端记录客户端信息 数据存放在服务端更加安全&a…

Leetcode JAVA刷刷站(14)最长公共前缀

一、题目概述 二、思路方向 在Java中,要编写一个函数来查找字符串数组中的最长公共前缀,我们可以遵循以下步骤: 处理边界条件:如果数组为空或长度为0,直接返回空字符串。初始化最长公共前缀:将数组的第一个…

[0CTF 2016]piapiapia1

打开题目 看到登录口 字符串绕过长度限制strlen($_POST[nickname]) > 10

Json Formatter工具

JSON 格式化工具的选择与使用 作为开发人员,我们经常需要查看和格式化 JSON 数据。虽然市面上有很多 JSON 工具可以满足这一需求,但在某些情况下,标准的 JSON 工具可能并不够用。 例如,处理一个 JavaScript 对象的格式&#xff…

【Qt】QWidget的windowTitle属性

QWidget的windowTitle属性 API说明 windowTitle() 获取到控件的窗⼝标题. setWindowTitle(const QString& title) 设置控件的窗⼝标题. 例子:设置窗口标题 当前windowTitle属性是从属于Qwidget的,Qwidget是一个广泛的定义,window…

Qt第十四章 模型视图

Model/View(模型/视图)结构 文章目录 Model/View(模型/视图)结构简介视图组件Model/View结构的一些概念项目控件组(item Widgets)模型/视图 如何使用项目视图组设置行的颜色交替变换拖拽设置编辑操作其他操作 选择模型自定义选择多…

打靶记录10——hacksudo---Thor

靶机: https://download.vulnhub.com/hacksudo/hacksudo---Thor.zip难度: 中 目标: 取得root权限flag 涉及攻击方法: 主机发现端口扫描Web目录爬取开源源码泄露默认账号密码SQL注入破壳漏洞GTFOBins提权 主机发现&#xff…

Windows的cmd命令行使用Linux类命令

Windows的cmd使用Linux类命令 去我的个人博客观看,观感更佳哦,😙😙 前言 我在使用Vscode编写C/C代码的时候,经常会用到Shell(你可以理解为命令行),但是我不得不说Windows下Dos命令极其难用且拉跨&#x1f…

【应用层协议】自定义协议 {定义结构化数据;数据格式转换:序列化和反序列化,使用json库进行数据格式交换;分包和解包:为报文内容添加报头}

一、简单了解TCP协议(引子) 1.1 三次握手 三次握手就是客户端向服务端发起连接的过程 服务器初始化 调用socket,创建套接字文件 调用bind,将当前的文件描述符和ip/port绑定在一起;如果这个端口已经被其他进程占用了&…

整理 酷炫 Flutter 开源UI框架 按钮

flutter_percent_indicator Flutter 百分比指示器库 项目地址:https://github.com/diegoveloper/flutter_percent_indicator 项目Demo:https://download.csdn.net/download/qq_36040764/89631340

springboot整合doris(doris创建表)

Doris 的数据模型主要分为 3 类: 明细模型(Duplicate Key Model):允许指定的 Key 列重复;适用于必须保留所有原始数据记录的情况主键模型(Unique Key Model):每一行的 Key 值唯一;可确保给定的 Key 列不会存在重复行聚合模型(Aggregate Key Model):可根据 Key 列聚…

力扣每日一题 特殊数组 II 前缀和

Problem: 3152. 特殊数组 II &#x1f468;‍&#x1f3eb; 参考题解 Code class Solution {public boolean[] isArraySpecial(int[] nums, int[][] queries) {int[] s new int[nums.length];for (int i 1; i < nums.length; i) {s[i] s[i - 1] (nums[i - 1] % 2 num…