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

【Linux】进程间通信——system V共享内存 | 消息队列 | 信号量

文章目录

  • 一、system V共享内存
    • 1. 共享内存的原理
    • 2. 共享内存相关函数
    • 3. 共享内存实现通信
    • 4. 共享内存的特点
  • 二、system V消息队列(了解)
  • 三、system V信号量(信号量)


一、system V共享内存

1. 共享内存的原理

共享内存是一种在多个进程之间进行进程间通信的机制。它允许多个进程访问相同的物理内存区域,从而实现高效的数据交换和通信。

因为进程具有独立性(隔离性),内核数据结构包括对应的代码、数据与页表都是独立的。OS系统为了让进程间进行通信,必须让不同的进程看到同一份资源。所以共享内存的原理如下:

1.申请一块空间
2.将创建好的内存映射进进程的地址空间。

共享内存让不同的进程看到同一份的资源就是在物理内存上申请一块内存空间,将创建好的内存分别与各个进程的页表之间建立映射,然后在虚拟地址空间中将虚拟地址填充到各自页表的对应位置,建立起物理地址与虚拟地址的联系。

在这里插入图片描述
在这里插入图片描述

我们把创建好的内存称为共享内存,把进程和共享内存建立映射关系的操作称为挂接,把取消进程和内存的映射关系称为去关联,把释放内存称为释放共享内存

共享内存的建立: 在物理内存当中申请共享内存空间;将申请到的共享内存挂接到地址空间,即建立映射关系。

共享内存的释放: 共享内存与地址空间去关联,即取消映射关系;释放共享内存空间,即将物理内存归还给系统。

对共享内存的理解:

  • 共享内存不属于通信的任意一个进程,其属于操作系统,由操作系统所管理。

  • 管道的本质是文件,操作系统已经有相应的内核数据结构来管理文件,因此不需要再去设计新的内核数据结构去管理管道。而共享内存是专门为了进程间通信而设计的,操作系统可能会有很多共享内存,那么操作系统就需要将这些共享内存管理起来。

  • 管理的方式是先描述再组织,那么共享内存就等于共享内存块加上共享内存对应的内核数据结构。

  • 对共享内存的修改包括对属性的修改和对内容的修改。


2. 共享内存相关函数

  • shmget: 用来创建或者获取共享内存。失败时返回-1。

在这里插入图片描述

参数:

shmflg: 通常被设置成两个选项: IPC_CREAT、 IPC_EXCL

  • IPC_CREAT:共享内存不存在,则创建,如果存在则获取;
  • IPC_EXCL:无法单独使用,IPC_CREAT | IPC_EXCL:如果不存在就创建,如果存在就出错返回

size: 共享内存的大小

key: 共享内存字段的名字,通信的进程需要通过该key值找到同一个共享内存,从而进行通信。因此key能保证多个进程看到同一份共享内存,能进行唯一性标识。

  • ftok: 生成key。失败时返回-1。

在这里插入图片描述

ftok函数将pathname和project id 经过一定的算法转换成 key,pathname必须存在,projectid不能为0。

OS一定会存在很多的共享内存,共享内存本质就是在内存中申请一块空间,而key能进行唯一标识。OS申请的,自然要做管理,共享内存也是如此,如何管理:先描述,在组织。所以共享内存=物理内存块+共享内存的相关属性。进程如果在内存中创建了共享内存,为了让共享内存在系统中保证唯一的,通过key来进行标识,只要让另一个进程也看到同一个key。

  • shmat:将共享内存段连接到进程地址空间(建立页表映射关系)。成功返回一个指针,指向共享内存第一个字节;失败返回 (void*) -1。

在这里插入图片描述

参数:

shmid: 共享内存的标识符。

shmaddr: 指定连接地址,如果设置为nullptr,则让操作系统指定连接到合适的地址上。

shmflg: 它的两个可能取值是 SHM_RND 和 SHM_RDONLY。shmflg 等于 SHM_RDONLY 时,表示连接操作用来只读共享内存。

  • shmdt: 将共享内存段与当前进程脱离。成功返回0,失败返回-1。

在这里插入图片描述

参数:

shmaddr: 由shmat函数所返回的指针。

这里我们需要注意:将共享内存和当前进程脱离不等于删除共享内存。

  • shmctl: 用语控制共享内存。

在这里插入图片描述

参数:

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

cmd: 将要采取的动作。(有三个可以选择)

buf: 为指向一个保存着共享内存的模式状态和访问权限的数据结构。不关心共享内存的内核数据结构时,buf可以设置为nullptr。

这里我们需要注意的是:当进程运行结束时,进程创建的共享内存还会存在,这是因为system V IPC资源的生命周期是随其内核的。其内核可以通过代码删除(shmctl函数),也可以通过ipcrm -m shmid 指令手动删除。使用ipcs -m 指令可以查看系统中已经创建好的共享内存。

在这里插入图片描述


3. 共享内存实现通信

makefile

.PHONY:all
all: shmclient shmservershmclient:client.ccg++ -o $@ $^ -std=c++11
shmserver:server.ccg++ -o $@ $^ -std=c++11.PHONY:clean
clean:rm -f shmclient shmserver

comm.hpp

#ifndef __COMM_HPP__
#define __COMM_HPP_#include <iostream>
#include <cstring>
#include <cstdio>
#include <cassert>
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <sys/stat.h>
using namespace std;#define PATHNAME "."
#define PROJID 0x6666const int gsize = 4096;//获取key
key_t getKey()
{key_t k = ftok(PATHNAME, PROJID);if(k == -1){cerr << "error: " << errno << " : " << strerror(errno) << endl;exit(1);}return k;
}//转十六进制函数
string toHex(int x)
{char buffer[64];snprintf(buffer, sizeof buffer, "0X%x", x);return buffer;
}//共享内存公共函数
static int createShmHelper(key_t k, size_t size, int flag)
{int shmid = shmget(k, size, flag);if(shmid == -1){cerr << "error: " << errno << " : " << strerror(errno) << endl;exit(2);}return shmid;
}//创建共享内存
int createShm(key_t k, size_t size)
{umask(0);return createShmHelper(k, size, IPC_CREAT | IPC_EXCL | 0666);
}//获取共享内存
int getShm(key_t k, size_t size)
{return createShmHelper(k, size, IPC_CREAT);
}//关联进程
char* attachShm(int shmid)
{char* start = (char*)shmat(shmid, nullptr, 0);return start;
}//去关联进程
void detachShm(char* start)
{int n = shmdt(start);assert(n != -1);(void)n;
}//释放共享内存
void delShm(int shmid)
{int n = shmctl(shmid, IPC_RMID, nullptr);assert(n != -1);(void)n;
}#define SERVER 1
#define CLIENT 0class Init
{
public:Init(int t):_type(t){key_t key = getKey();if(_type == SERVER)_shmid = createShm(key, gsize);else_shmid = getShm(key, gsize);_start = attachShm(_shmid);           }char* getChar(){return _start;}~Init(){detachShm(_start);if(_type == SERVER) delShm(_shmid);}
private:char* _start;int _type; // server or clientint _shmid;
};#endif

服务端:server.cc

#include "comm.hpp"int main()
{Init init(SERVER);char* start = init.getChar();int n = 0;while(n <= 35){cout <<"client -> server# "<< start << endl;sleep(1);n++;}// // 1. 创建key// key_t k = getKey();// cout << "server:" << toHex(k) << endl;// // 2. 创建共享内存// int shmid = createShm(k, gsize);// cout << "shmid:" << shmid << endl;// sleep(8);// // 3. 将自己和共享内存关联起来// char* start = attachShm(shmid);// sleep(20);// // 4. 将自己和共享内存去关联// detachShm(start);// sleep(3);// 5. 删除共享内存// delShm(shmid);return 0;
}

客户端:client

#include "comm.hpp"int main()
{Init init(CLIENT);char *start = init.getChar();char c = 'A';while(c <= 'Z'){start[c - 'A'] = c;c++;start[c - 'A'] = '\0';sleep(1);}// // 1. 获取key// key_t k = getKey();// cout << "client:" << toHex(k) << endl;// // 2. 获取共享内存// int shmid = getShm(k, gsize);// cout << "shmid:" << shmid << endl;// // 3. 将自己和共享内存关联起来// char* start = attachShm(shmid);// sleep(15);// // 4. 将自己和共享内存去关联// detachShm(start);return 0;
}

在这里插入图片描述


4. 共享内存的特点

优点:

  • 只要通信双方使用共享内存,一方直接向共享内存中写入数据,另一方就可以马上看到对方写入的数据。共享内存是所有进程间通信(IPC)中速度最快的!因为其不需要过多的拷贝(不需要将数据给操作系统)

下面我们来比对一下共享内存和管道:

管道通信的拷贝:

C++输入设备把数据拷贝到cin或者stdin文件缓存区不考虑,这里总共进行了4次拷贝。

在这里插入图片描述

共享内存通信的拷贝:

直接从输入到共享内存,从共享内存到输出。

在这里插入图片描述

缺点:

以共享内存的方式进行进程间通信缺乏访问控制,会带来同步问题!比如:写端还没将全部数据写入,读端就已经开始读取了,这将会带来巨大的问题!


二、system V消息队列(了解)

消息队列 是OS提供的内核级队列,消息队列提供了一个从一个进程向另外一个进程发送一块数据的方法,每个数据块都被认为是有一个类型,接收者进程接收的数据块可以有不同的类型值。

  • 消息队列提供了一个从一个进程向另外一个进程发送一块数据的方法。
  • 每个数据块都被认为是有一个类型,接收者进程接收的数据块可以有不同的类型值。
  • IPC资源必须删除,否则不会自动清除,除非重启,所以system V IPC资源的生命周期随内核

常用系统调用:ftok,msgget(创建消息队列),msgctl(控制消息队列),msgsnd(向消息队列发送数据),msgrcv(从消息队列中读取数据)等。

在这里插入图片描述


三、system V信号量(信号量)

下面,我们先来引出几个概念:

"公共资源:" 被多个进程同时访问的资源,访问没有保护的公共资源:数据不一致问题。要让不同的进程看到同一份资源是为了通信,通信是为了让进程间实现协同,而进程之间具有独立性,所以为了解决独立性问题要让进程看到同一份资源,但是会导致数据不一致的问题。

"互斥": 任何一个时刻,都只允许一个执行流在进行共享资源的访问。各进程间竞争使用这些资源,竞争的这种关系为进程的互斥。

"临界资源": 任何一个时刻,都只允许一个执行流在进行访问的共享资源,叫做临界资源。

"临界区": 临界资源是需要通过代码访问的,凡是访问临界资源的代码,叫做临界区。

"原子性": 要么不做、要么做完,只有两种确定状态的属性,叫做原子性。

任何一个执行流,想访问临界资源中的一个子资源时,不能直接访问。得先申请信号量,信号量/信号灯 本质是一个计数器,描述资源数量的计数器。 信号量是对临界资源的预定机制。

  • 申请信号量
    只要申请信号量成功,临界资源内部一定给你预留了你想要的资源,申请信号量本质是对临界资源的一种预定机制,让信号计数器减减,信号量计数器为0时,进程申请信号量无法成功。只能阻塞等待其他进程退出,才能申请信号量,访问临界资源。
  • 访问临界资源——进程执行自己的临界区代码
  • 释放信号量——信号量计数器加加

在这里插入图片描述
在这里插入图片描述

我们可以发现,共享内存、消息队列、信号量接口相似度非常高,获取与删除,都是system V标准的进程间通信。

OS如何管理:先描述,在组织,对相关资源的内核数据结构做管理,对于共享内存、消息队列、信号量的第一个成员都是ipc_perm:

struct ipc_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 andSHM_LOCKED flags */unsigned short __seq;    /* Sequence number */
};

虽然内部的属性差别很大,但是维护它们的数据结构的第一个成员都是ipc_perm类型的成员变量,都可以通过key来标识唯一性。这样设计的好处:在操作系统内可以定义一个struct ipc_perm类型的数组,此时每当我们申请一个IPC资源,就在该数组当中开辟一个这样的结构。((struct shmid_ds*)perms[0],强转,此时就可以访问其他剩下的属性)

在这里插入图片描述


相关文章:

【Linux】进程间通信——system V共享内存 | 消息队列 | 信号量

文章目录 一、system V共享内存1. 共享内存的原理2. 共享内存相关函数3. 共享内存实现通信4. 共享内存的特点 二、system V消息队列&#xff08;了解&#xff09;三、system V信号量&#xff08;信号量&#xff09; 一、system V共享内存 1. 共享内存的原理 共享内存是一种在…...

CentOS实现html转pdf

CentOS使用实现html转PDF&#xff0c;需安装以下软件&#xff1a; yum install wkhtmltopdf # 转换工具&#xff0c;将HTML文件或网页转换为PDFyum install xorg-x11-server-Xvfb # 虚拟的X服务器&#xff0c;在无图形界面环境下运行图形应用程yum install wqy-zenhei-fonts #…...

【C++】基于多设计模式下的同步异步日志系统

✍作者&#xff1a;阿润021 &#x1f4d6;专栏&#xff1a;C 文章目录 一、项目介绍二、项目实现准备工作1.日志系统技术实现策略2.相关技术知识补充2.1 不定参函数设计2.2 设计模式 三、日志项目框架设计1.模块划分2.各模块关系图 四、详细代码实现1.实用工具类设计2.日志等级…...

防火墙监控工具

防火墙监控是跟踪在高效防火墙性能中起着关键作用的重要防火墙指标&#xff0c;防火墙监控通常应包括&#xff1a; 防火墙日志监控防火墙规则监控防火墙配置监控防火墙警报监控 防火墙监控服务的一个重要方面是它应该是主动的。主动识别内部和外部安全威胁有助于在早期阶段识…...

组合模式——树形结构的处理

1、简介 1.1、概述 树形结构在软件中随处可见&#xff0c;例如操作系统中的目录结构、应用软件中的菜单、办公系统中的公司组织结构等。如何运用面向对象的方式来处理这种树形结构是组合模式需要解决的问题。组合模式通过一种巧妙的设计方案使得用户可以一致性地处理整个树形…...

从实体按键看 Android 车载的自定义事件机制

作者&#xff1a;TechMerger 在汽车数字化、智能化变革的进程中&#xff0c;越来越多的车机设计或部分、或全部地舍弃了实体按键&#xff0c;进而把车主操作的入口转移到了车机 UI 以及语音助手。 但统一、高效的零层级 UI 颇为困难&#xff0c;语音的准确率、覆盖率亦不够完善…...

nosql之redis集群

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 一、redis集群1.单节点redis服务器带来的问题2.集群redis3.集群的优势4.redis集群的实现方法5.redis群集的三种模式5.1 主从复制5.2 哨兵5.3 集群 二、Redis 主从复…...

SpringBoot 项目使用 Redis 对用户 IP 进行接口限流

一、思路 使用接口限流的主要目的在于提高系统的稳定性&#xff0c;防止接口被恶意打击&#xff08;短时间内大量请求&#xff09;。 比如要求某接口在1分钟内请求次数不超过1000次&#xff0c;那么应该如何设计代码呢&#xff1f; 下面讲两种思路&#xff0c;如果想看代码可…...

SLA探活工具EaseProbe

工具介绍 EaseProbe可以做三种工作&#xff1a;探测、通知和报告。 项目地址&#xff1a;https://github.com/megaease/easeprobe 1、安装 [rootlocalhost ]# yum -y install unzip go [rootlocalhost ]# unzip easeprobe-main.zip [rootlocalhost ]# cd easeprobe-main [r…...

[Java] 观察者模式简述

模式定义&#xff1a;定义了对象之间的一对多依赖&#xff0c;让多个观察者对象同时监听某一个主题对象&#xff0c;当主题对象发生变化时&#xff0c;他的所有依赖者都会收到通知并且更新 依照这个图&#xff0c;简单的写一个代码 package Section1.listener;import java.ut…...

linux驱动定时器实现按键按下打印字符

#include <linux/init.h> #include <linux/module.h> #include <linux/of.h> #include <linux/of_irq.h> #include <linux/interrupt.h>struct device_node *dev; unsigned int irqno; //中断处理函数 irqreturn_t myirq_handler(int irq,void *…...

反转链表(JS)

反转链表 题目 给你单链表的头节点 head &#xff0c;请你反转链表&#xff0c;并返回反转后的链表。 示例 1&#xff1a; 输入&#xff1a;head [1,2,3,4,5] 输出&#xff1a;[5,4,3,2,1]示例 2&#xff1a; 输入&#xff1a;head [1,2] 输出&#xff1a;[2,1]示例 3&…...

[PyTorch][chapter 45][RNN_2]

目录&#xff1a; RNN 问题 RNN 时序链问题 RNN 词组预测的例子 RNN简洁实现 一 RNN 问题 RNN 主要有两个问题&#xff0c;梯度弥散和梯度爆炸 1.1 损失函数 梯度 其中&#xff1a; 则 1.1 梯度爆炸&#xff08;Gradient Exploding&#xff09; 上面矩阵进行连乘后…...

基于canvas画布的实用类Fabric.js的使用

目录 前言 一、Fabric.js简介 二、开始 1、引入Fabric.js 2、在main.js中使用 3、初始化画布 三、方法 四、事件 1、常用事件 2、事件绑定 3、事件解绑 五、canvas常用属性 六、对象属性 1、基本属性 2、扩展属性 七、图层层级操作 八、复制和粘贴 1、复制 2…...

基于SpringBoot+Vue驾校理论课模拟考试系统源码(自动化部署)

DrivingTestSimulation Unity3D Project, subject two, simulated driving test 【更新信息】 更新时间-2021-1-17 解决了方向盘不同机型转动轴心偏离 更新时间-2021-2-18 加入了手刹系统 待更新-2021-6-19&#xff08;工作太忙少有时间更新&#xff0c;先指出问题&#xf…...

SpringBoot使用Redis对用户IP进行接口限流

使用接口限流的主要目的在于提高系统的稳定性&#xff0c;防止接口被恶意打击&#xff08;短时间内大量请求&#xff09;。 一、创建限流注解 引入redis依赖 <!--redis--><dependency><groupId>org.springframework.boot</groupId><artifactId&g…...

MeterSphere学习篇

从开发环境部署开始 metersphere-1.20.4 源码下载地址&#xff1a; https://gitee.com/fit2cloud-feizhiyun/MeterSphere/tree/v1.20/ MeterSphere GitHub 相关插件程序下载 相关准备 安装mysql 配置IDEA...

大数据技术之Clickhouse---入门篇---数据类型、表引擎

星光下的赶路人star的个人主页 今天没有开始的事&#xff0c;明天绝对不会完成 文章目录 1、数据类型1.1 整型1.2 浮点型1.3 布尔型1.4 Decimal型1.5 字符串1.6 枚举类型1.7 时间类型1.8 数组 2、表引擎2.1 表引擎的使用2.2 TinyLog2.3 Memory2.4 MergeTree2.4.1 Partition by分…...

【微服务架构设计】微服务不是魔术:处理超时

微服务很重要。它们可以为我们的架构和团队带来一些相当大的胜利&#xff0c;但微服务也有很多成本。随着微服务、无服务器和其他分布式系统架构在行业中变得更加普遍&#xff0c;我们将它们的问题和解决它们的策略内化是至关重要的。在本文中&#xff0c;我们将研究网络边界可…...

天下风云出我辈,AI准独角兽实在智能获评“十大数字经济风云企业

时值盛夏&#xff0c;各地全力拼经济的氛围同样热火朝天。在浙江省经济强区余杭区这片创业热土上&#xff0c;人工智能助力数字经济建设正焕发出蓬勃生机。 7月28日&#xff0c;经专家评审、公开投票&#xff0c;由中共杭州市余杭区委组织部&#xff08;区委两新工委&#xff…...

【Oracle APEX开发小技巧12】

有如下需求&#xff1a; 有一个问题反馈页面&#xff0c;要实现在apex页面展示能直观看到反馈时间超过7天未处理的数据&#xff0c;方便管理员及时处理反馈。 我的方法&#xff1a;直接将逻辑写在SQL中&#xff0c;这样可以直接在页面展示 完整代码&#xff1a; SELECTSF.FE…...

2024年赣州旅游投资集团社会招聘笔试真

2024年赣州旅游投资集团社会招聘笔试真 题 ( 满 分 1 0 0 分 时 间 1 2 0 分 钟 ) 一、单选题(每题只有一个正确答案,答错、不答或多答均不得分) 1.纪要的特点不包括()。 A.概括重点 B.指导传达 C. 客观纪实 D.有言必录 【答案】: D 2.1864年,()预言了电磁波的存在,并指出…...

连锁超市冷库节能解决方案:如何实现超市降本增效

在连锁超市冷库运营中&#xff0c;高能耗、设备损耗快、人工管理低效等问题长期困扰企业。御控冷库节能解决方案通过智能控制化霜、按需化霜、实时监控、故障诊断、自动预警、远程控制开关六大核心技术&#xff0c;实现年省电费15%-60%&#xff0c;且不改动原有装备、安装快捷、…...

《用户共鸣指数(E)驱动品牌大模型种草:如何抢占大模型搜索结果情感高地》

在注意力分散、内容高度同质化的时代&#xff0c;情感连接已成为品牌破圈的关键通道。我们在服务大量品牌客户的过程中发现&#xff0c;消费者对内容的“有感”程度&#xff0c;正日益成为影响品牌传播效率与转化率的核心变量。在生成式AI驱动的内容生成与推荐环境中&#xff0…...

ardupilot 开发环境eclipse 中import 缺少C++

目录 文章目录 目录摘要1.修复过程摘要 本节主要解决ardupilot 开发环境eclipse 中import 缺少C++,无法导入ardupilot代码,会引起查看不方便的问题。如下图所示 1.修复过程 0.安装ubuntu 软件中自带的eclipse 1.打开eclipse—Help—install new software 2.在 Work with中…...

(一)单例模式

一、前言 单例模式属于六大创建型模式,即在软件设计过程中,主要关注创建对象的结果,并不关心创建对象的过程及细节。创建型设计模式将类对象的实例化过程进行抽象化接口设计,从而隐藏了类对象的实例是如何被创建的,封装了软件系统使用的具体对象类型。 六大创建型模式包括…...

Unity UGUI Button事件流程

场景结构 测试代码 public class TestBtn : MonoBehaviour {void Start(){var btn GetComponent<Button>();btn.onClick.AddListener(OnClick);}private void OnClick(){Debug.Log("666");}}当添加事件时 // 实例化一个ButtonClickedEvent的事件 [Formerl…...

Elastic 获得 AWS 教育 ISV 合作伙伴资质,进一步增强教育解决方案产品组合

作者&#xff1a;来自 Elastic Udayasimha Theepireddy (Uday), Brian Bergholm, Marianna Jonsdottir 通过搜索 AI 和云创新推动教育领域的数字化转型。 我们非常高兴地宣布&#xff0c;Elastic 已获得 AWS 教育 ISV 合作伙伴资质。这一重要认证表明&#xff0c;Elastic 作为 …...

鸿蒙(HarmonyOS5)实现跳一跳小游戏

下面我将介绍如何使用鸿蒙的ArkUI框架&#xff0c;实现一个简单的跳一跳小游戏。 1. 项目结构 src/main/ets/ ├── MainAbility │ ├── pages │ │ ├── Index.ets // 主页面 │ │ └── GamePage.ets // 游戏页面 │ └── model │ …...

C++实现分布式网络通信框架RPC(2)——rpc发布端

有了上篇文章的项目的基本知识的了解&#xff0c;现在我们就开始构建项目。 目录 一、构建工程目录 二、本地服务发布成RPC服务 2.1理解RPC发布 2.2实现 三、Mprpc框架的基础类设计 3.1框架的初始化类 MprpcApplication 代码实现 3.2读取配置文件类 MprpcConfig 代码实现…...