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

Linux之进程间通信(system V 共享内存)

目录

一、共享内存

1、基本原理

2、共享内存的创建

3、共享内存的释放

4、共享内存的关联

5、共享内存的去关联

6、查看IPC资源

二、完整通信代码

三、共享内存的特点

四、信号量

1、相关概念

2、信号量概念


进程间通信的本质就是让不同的进程看到同一个资源。而前面我们讲到了进程通信的最基础,最传统的方法——管道。我们知道了,无论是匿名管道还是命名管道,它们让不同进程看到同样的资源的方法,就是通过访问同样的文件来看到同样的资源。

进程间是相互独立的,因此进程的各种数据是存储在物理内存的不同区域的。那么,如果两个不同的进程能够访问到同一块内存空间,是不是就相当于看到了同样的资源。那么有没有这样的方法呢?答案是肯定的,system V中的共享内存就是这样的一种进程间通信的方法。

一、共享内存

1、基本原理

在学习了进程地址空间后,我们知道,在堆和栈之间有一块空间叫做共享区。

我们在物理内存中申请了一块空间,然后通过页表将这块空间,映射到不同进程的进程地址空间的共享区中, 然后再将映射到共享区的地址返回给各自的进程。那么,不同的进程就可以通过拿到虚拟地址,找到共享区,接着通过页表映射,找到物理内存。

这样,不同的进程就能够看到同一块空间了。这种工作方式就叫做共享内存。

如果想结束通信,我们直接取消进程和内存的映射关系,释放共享内存。

共享内存的提供者是操作系统,而操作系统中可能会有多个共享内存,所以操作系统必定需要将各个共享内存管理起来,怎么管理呢?当然是,先描述,再组织。

所以,共享内存包括了共享内存块和描述共享内存的内核数据结构。

2、共享内存的创建

shmget :作用是用来创建共享内存。返回值:shmid:共享内存的用户层标识符(类似于fd)。

#include <sys/ipc.h>
#include <sys/shm.h>int shmget(key_t key, size_t size, int shmflg);RETURN VALUEOn success, a valid shared memory identifier is returned.  On errir, -1 is returned, and errno is set to indicate the error

参数说明

size:创建的共享内存的大小。

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

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

key:当一个进程将共享内存创建好了,而与之通信的另一个进程怎么保证看到的就是我创建的共享内存呢?key值就可以解决这个问题。

OS中一定会存在很多的共享内存,共享内存本质就是在内存中申请一块空间,而key能对其进行唯一标识。进程如果在内存中创建了共享内存,为了让共享内存在系统中保证唯一的,通过key来进行标识,所以只要让另一个进程也看到同一个key,那么不同的进程就能看到同一个共享内存。而key值就在描述共享内存的内核结构体struct shm中。

 那么,我们应该给key传入什么值呢:使用 ftok函数来形成key。

ftok:

#include <sys/types.h>
#include <sys/ipc.h>
key_t ftok(const char *pathname, int proj_id);RETURN VALUEOn success, the generated key_t value is returned.  On failure -1 is returned, with errno indicating the error as for the stat(2) system call.

3、共享内存的释放

因为共享内存是由操作系统提供并管理的,所以共享内存的生命周期是随操作系统,而不是随进程的。所以我们在使用完共享内存后,需要用户亲自删除。

1、使用命令删除:ipcrm -m shmid

2、使用代码函数删除

shmctl:作用是删除共享内存。参数:shmid:删除共享内存的标识符,cmd:控制种类(一般使用 IPC_RMID),buf:控制共享内存的数据结构,可以简单设置为空(nullptr)。

返回值:0表示成功,-1表示失败。

 #include <sys/ipc.h>#include <sys/shm.h>int shmctl(int shmid, int cmd, struct shmid_ds *buf);

4、共享内存的关联

shmat:作用是将共享内存与对应的进程关联起来。我们把进程和共享内存建立映射关系的操作称为挂接。

 #include <sys/types.h>#include <sys/shm.h>void *shmat(int shmid, const void *shmaddr, int shmflg);

参数:shmaddr:指定虚拟地址,但是我们并不了解,直接设置为nullptr即可;shmflg:读取权限,默认为0。

5、共享内存的去关联

shmdt:作用是将共享内存与对应的进程的关联解除。我们把取消进程和内存的映射关系的操作称为去关联。shmaddr:指定虚拟地址。

#include <sys/types.h>
#include <sys/shm.h>
int shmdt(const void *shmaddr);RETURN VALUE
On  success  shmdt() returns 0; on error -1 is returned, and errno is set to indi‐cate the cause of the error.

6、查看IPC资源

1、查看共享内存:ipcs -m      bytes:共享内存大小(最后是页PAGE:4096的整数倍)    nattch:与该共享内存关联的进程个数

owner:共享内存的拥有者。 perms:拥有者对于该共享内存的权限

2、删除共享内存:ipcsrm -m  shmid

3、ipcs -q:查看消息队列

4、ipcs -s:查看信号量

二、完整通信代码

shmcoom.hpp

#pragma once#include<iostream>
#include<cassert>
#include<cstring>
#include<sys/types.h>
#include<sys/stat.h>
#include<sys/shm.h>
#include<sys/ipc.h>
#include<unistd.h>using namespace std;#define SHM_SIZE 4096
#define PATH_NAME "/home/zdl"
#define PROJ_ID 0x66

server.cc

#include "shmcomm.hpp"int main()
{// 1.创建key值key_t k = ftok(PATH_NAME, PROJ_ID);assert(k != -1);printf("key: %d\n", k);// 2.创建共享内存int shmid = shmget(k, SHM_SIZE, IPC_CREAT | IPC_EXCL | 0666);if (shmid == -1){perror("shmget");exit(1);}// 3.关联共享内存char *shmaddr = (char *)shmat(shmid, nullptr, 0);if (shmaddr == nullptr){perror("shmat");exit(2);}// 4.进程间通信for (;;){printf("%s\n", shmaddr);if (strcmp(shmaddr, "quit") == 0)break;sleep(1);}// 5.去关联int m = shmdt(shmaddr);assert(m != -1);(void)m;// 6。删除共享内存int n = shmctl(shmid, IPC_RMID, nullptr);assert(n != -1);(void)n;return 0;
}

 client.cc

#include "shmcomm.hpp"int main()
{// 获取key值key_t k = ftok(PATH_NAME, PROJ_ID);assert(k != -1);printf("key: %d\n", k);// 获取共享内存int shmid = shmget(k, SHM_SIZE, IPC_CREAT);if (shmid == -1){perror("shmget");exit(1);}// 挂接char *shmaddr = (char *)shmat(shmid, nullptr, 0);if (shmaddr == nullptr){perror("shmat");exit(2);}// 进程间通信int count = 0;while (count < 10){snprintf(shmaddr, SHM_SIZE - 1, "hello server,我是另一个进程,正在和你通信,我的pid:%d count: %d",getpid(), count++);sleep(1);}strcpy(shmaddr, "quit");// 去关联int m = shmdt(shmaddr);assert(m != -1);(void)m;return 0;
}

运行结果

首先,我们看到的是,两个进程的key值相同,且shmserver在输入了quit后,进程退出,shmclient也退出。 

三、共享内存的特点

优点:共享内存是所有进程间通信速度是最快的,因为共享内存是被双方所共享,只要写入对方就能立即看到,能大大减少数据的拷贝次数。

具体说明:

管道:我们知道,管道的本质是一个文件,所以我们必须像使用文件那样去使用管道,即我们想要通信就必须调用系统接口。具体如下图:

需要通过键盘输入到自己定义的缓冲区char buffer[],将数据拷贝到buffer中,调用write接口在把buffer里的数据拷贝到管道里,另一进程也有定义buffer缓冲区,调用read读取把数据从管道里读取到buffer里,再把数据显示到显示器上。

从上图,我们看到:使用管道要进行四次拷贝。 

共享内存:只需要两次拷贝。

缺点:与管道相比,共享内存没有访问控制,会出现数据不一致问题。即:读取的一方不会因为内存中没有数据或数据还没有写入而停止读取,写入的一方也不会考虑另一方是否读取,而会一直写入。如果想做到访问控制需要用到信号量或使用管道,对共享内存进行保护。

四、信号量

1、相关概念

1、临界资源:我们把多个进程(执行流)看到的公共资源称为临界资源或互斥资源。

2、临界区:我们把自己的进程中,访问临界资源的那部分代码称为临界区。

所以说,如果我们不加保护地访问了临界资源,那么多个执行流在运行时会互相干扰,而在非临界区多个执行流互不影响。

3、互斥:为了更好地保护临界资源,我们要让多个执行流,在任意时刻,只允许一个执行流进入临界资源,去访问临界资源,这种方式就称为互斥。

4、原子性:只要两态,要么不做、要么做完,没有中间状态。

2、信号量概念

引入:为了保护共享资源,我们必须保证进程间是互斥的。如果在同一时刻,不同的执行流要访问的是临界资源的不同区域,那么我们是允许它们同时进入共享内存进行资源访问的。比如,临界资源中有10个区域,那么我们最多就可以同时让10个执行流进入进行资源访问(这10个执行流能够并发地访问临界资源)。而当第11个执行流想要进入时,它就必须要等待,只有它需要的区域没有执行流在访问时,它才能去访问临界资源。

这时,我们就使用了信号量来对临界资源进行保护。

信号量:信号量的本质是一个计数器,通常用来表示临界资源中,资源数的多少。申请信号量实际上就是对临界资源的预定机制。信号量主要用于同步和互斥。

比如,还是上面的例子,信号量会是10,当有不同的10个执行流(访问临界资源的10个不同区域)想要访问临界资源时,它们会先申请信号量(信号量--),然后操作系统一定会在共享内存中为执行流预留好它想要的资源,可以随时访问。而当第11个执行流去申请信号量时,信号量为0,所以该执行流还无法访问临界资源。

只有当其中的一个执行流访问完临界资源,释放信号量后(信号量++),第11个执行流才能够申请信号量,去访问临界资源。

相关文章:

Linux之进程间通信(system V 共享内存)

目录 一、共享内存 1、基本原理 2、共享内存的创建 3、共享内存的释放 4、共享内存的关联 5、共享内存的去关联 6、查看IPC资源 二、完整通信代码 三、共享内存的特点 四、信号量 1、相关概念 2、信号量概念 进程间通信的本质就是让不同的进程看到同一个资源。而前…...

数据库 sql select *from account where name=‘张三‘ 执行过程

select *from account where name张三分析上面语句的执行过程 用到了索引 由于是根据 1.name字段进行查询&#xff0c;所以先根据name张三’到name字段的二级索引中进行匹配查 找。但是在二级索引中只能查找到 Arm 对应的主键值 10。 2.由于查询返回的数据是*&#xff0c…...

力扣日记1.27-【回溯算法篇】131. 分割回文串

力扣日记&#xff1a;【回溯算法篇】131. 分割回文串 日期&#xff1a;2023.1.27 参考&#xff1a;代码随想录、力扣 131. 分割回文串 题目描述 难度&#xff1a;中等 给你一个字符串 s&#xff0c;请你将 s 分割成一些子串&#xff0c;使每个子串都是 回文串 。返回 s 所有可…...

如何用web界面打开华为防火墙

目录 1.创建一个虚拟网卡 2.cloud操作 3.防火墙上操作 4. 登录 1.创建一个虚拟网卡 2.cloud操作 3.防火墙上操作 4. 登录...

力扣20、有效的括号(简单)

1 题目描述 图1 题目描述 2 题目解读 给定的字符串只包含括号&#xff0c;判断这个字符串中的括号是否按照正确顺序出现&#xff0c;即这个字符串是否有效。 3 解法一&#xff1a;栈 C的STL中的stack&#xff0c;在解题时非常好用。 3.1 解题思路 使用栈stk&#xff0c;并枚举…...

Android 系统启动过程

当按下电源时&#xff0c;引导芯片代码会从预定义的地方(固化在ROM) 开始执行,加载引导程序BootLoader到RAM,然后执行。 启动内核的第一个进程idle(pid0),idle进程是Linux系统第一个进程&#xff0c;是init进程和kthreadd进程的父进程。 idle的主要作用 初始化进程以及内存管…...

基于STM32的智能手环设计与实现

需要原理图工程&#xff0c;源码&#xff0c;PCB工程的朋友收藏&#xff0c;这篇文章关注我&#xff0c;私我吧&#xff01;&#xff01;&#xff01; 基于STM32的智能手环设计与实现 摘要一、研究背景及意义二、实现功能三、系统方案设计系统方案设计框图3.1 单片机芯片选择3…...

[BJDCTF2020]The mystery of ip

hint 猜测ip和XFF有关 加一个XFF 下面这一步是看了wp出来的&#xff1a;存在ssti 这里尝试用jinja的注入方法&#xff0c;页面回显了是php的smarty框架 查了一下smarty的注入方法&#xff0c;发现可以直接执行php命令 在根目录找到flag...

RUST笔记:candle使用基础

candle介绍 candle是huggingface开源的Rust的极简 ML 框架。 candle-矩阵乘法示例 cargo new myapp cd myapp cargo add --git https://github.com/huggingface/candle.git candle-core cargo build # 测试&#xff0c;或执行 cargo ckeckmain.rs use candle_core::{Device…...

Python算法题集_接雨水

本文为Python算法题集之一的代码示例 题目42&#xff1a;接雨水 说明&#xff1a;给定 n 个非负整数表示每个宽度为 1 的柱子的高度图&#xff0c;计算按此排列的柱子&#xff0c;下雨之后能接多少雨水 示例 1&#xff1a; 输入&#xff1a;height [0,1,0,2,1,0,1,3,2,1,2,1]…...

FIND_IN_SET的使用:mysql表数据多角色、多用户查询

MySQL 函数 FIND_IN_SET 是用于在逗号分隔的字符串中查找特定值的函数。它的语法如下&#xff1a; FIND_IN_SET(search_value, comma_separated_string)search_value 是要查找的值。 comma_separated_string 是逗号分隔的字符串&#xff0c;在这个字符串中查找指定的值。FIND_…...

JVM篇----第十一篇

系列文章目录 文章目录 系列文章目录前言一、在新生代-复制算法二、在老年代-标记整理算法三、分区收集算法四、GC 垃圾收集器前言 前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站,这篇文章男女通用,看懂了就去分享给你…...

鸿蒙HarmonyOS获取GPS精确位置信息

参考官方文档 #1.初始化时获取经纬度信息 aboutToAppear() {this.getLocation() } async getLocation () {try {const result await geoLocationManager.getCurrentLocation()AlertDialog.show({message: JSON.stringify(result)})}catch (error) {AlertDialog.show({message…...

java正则校验,手机号,邮箱,日期格式,时间格式,数字金额两位小数

java正则校验&#xff0c;手机号&#xff0c;邮箱&#xff0c;日期格式&#xff0c;时间格式&#xff0c;数字金额两位小数 3.58是否为金额&#xff1a;true 3.582是否为金额&#xff1a;false 1284789qq.com是否为email&#xff1a;true 1284789qq.com是否为email&#xff1…...

php下curl发送cookie

目录 一&#xff1a;使用 CURLOPT_COOKIE 选项 二&#xff1a;CURLOPT_COOKIEFILE 三&#xff1a;CURLOPT_HTTPHEADER php curl发送cookie的几种方式,下面来介绍下 一&#xff1a;使用 CURLOPT_COOKIE 选项 通过设置 CURLOPT_COOKIE 选项&#xff0c;你可以将 cookie 字符…...

stable diffusion学习笔记——文生图(一)

模型设置 基本模型 基本模型也就是常说的checkpoint&#xff08;大模型&#xff09;&#xff0c;基本模型决定了生成图片的主体风格。 如上图所示&#xff0c;基本模型的后缀为.safetensors。需要存放在特定的文件夹下。 如果用的是启动器&#xff0c;可以在启动器内直接下载。…...

Linux下安装openresty

Linux下安装openresty 十一、Linux下安装openresty11.1.概述11.2.下载OpenResty并安装相关依赖&#xff1a;11.3.使用wget下载:11.4.解压缩:11.5.进入OpenResty目录:11.6.编译和安装11.7.进入OpenResty的目录&#xff0c;找到nginx&#xff1a;11.8.在conf目录下的nginx.conf添…...

【IM】如何保证消息可用性(一)

目录 1. 基本概念1.1 长连接 和 短连接1.2 PUSH模式和PULL模式 2. 背景介绍2.1 理解端到端的思想 3. 方案选型3.1 技术挑战3.2 技术目标 1. 基本概念 在讲解消息可用性之前&#xff0c;需要理解几个通信领域的基本概念。 1.1 长连接 和 短连接 什么是长连接&#xff0c;短连接…...

js直接下载附件和通过blob数据类型下载文件

js下载文件方式有使用a标签的&#xff0c;也有直接用window.open的&#xff0c;还有用form表单的&#xff1b;这里采用的是a标签的下载方式&#xff0c;一种是url直接下载&#xff0c;另一种是文件的blob数据类型进行下载。 文件blob数据类型的获取一般是后端返回文件的二进制流…...

第2章-神经网络的数学基础——python深度学习

第2章 神经网络的数学基础 2.1 初识神经网络 我们来看一个具体的神经网络示例&#xff0c;使用 Python 的 Keras 库 来学习手写数字分类。 我们这里要解决的问题是&#xff0c; 将手写数字的灰度图像&#xff08;28 像素28 像素&#xff09;划分到 10 个类别 中&#xff08;0…...

Linux 文件类型,目录与路径,文件与目录管理

文件类型 后面的字符表示文件类型标志 普通文件&#xff1a;-&#xff08;纯文本文件&#xff0c;二进制文件&#xff0c;数据格式文件&#xff09; 如文本文件、图片、程序文件等。 目录文件&#xff1a;d&#xff08;directory&#xff09; 用来存放其他文件或子目录。 设备…...

论文解读:交大港大上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(二)

HoST框架核心实现方法详解 - 论文深度解读(第二部分) 《Learning Humanoid Standing-up Control across Diverse Postures》 系列文章: 论文深度解读 + 算法与代码分析(二) 作者机构: 上海AI Lab, 上海交通大学, 香港大学, 浙江大学, 香港中文大学 论文主题: 人形机器人…...

阿里云ACP云计算备考笔记 (5)——弹性伸缩

目录 第一章 概述 第二章 弹性伸缩简介 1、弹性伸缩 2、垂直伸缩 3、优势 4、应用场景 ① 无规律的业务量波动 ② 有规律的业务量波动 ③ 无明显业务量波动 ④ 混合型业务 ⑤ 消息通知 ⑥ 生命周期挂钩 ⑦ 自定义方式 ⑧ 滚的升级 5、使用限制 第三章 主要定义 …...

NFT模式:数字资产确权与链游经济系统构建

NFT模式&#xff1a;数字资产确权与链游经济系统构建 ——从技术架构到可持续生态的范式革命 一、确权技术革新&#xff1a;构建可信数字资产基石 1. 区块链底层架构的进化 跨链互操作协议&#xff1a;基于LayerZero协议实现以太坊、Solana等公链资产互通&#xff0c;通过零知…...

Kafka入门-生产者

生产者 生产者发送流程&#xff1a; 延迟时间为0ms时&#xff0c;也就意味着每当有数据就会直接发送 异步发送API 异步发送和同步发送的不同在于&#xff1a;异步发送不需要等待结果&#xff0c;同步发送必须等待结果才能进行下一步发送。 普通异步发送 首先导入所需的k…...

比较数据迁移后MySQL数据库和OceanBase数据仓库中的表

设计一个MySQL数据库和OceanBase数据仓库的表数据比较的详细程序流程,两张表是相同的结构,都有整型主键id字段,需要每次从数据库分批取得2000条数据,用于比较,比较操作的同时可以再取2000条数据,等上一次比较完成之后,开始比较,直到比较完所有的数据。比较操作需要比较…...

vue3 daterange正则踩坑

<el-form-item label"空置时间" prop"vacantTime"> <el-date-picker v-model"form.vacantTime" type"daterange" start-placeholder"开始日期" end-placeholder"结束日期" clearable :editable"fal…...

使用SSE解决获取状态不一致问题

使用SSE解决获取状态不一致问题 1. 问题描述2. SSE介绍2.1 SSE 的工作原理2.2 SSE 的事件格式规范2.3 SSE与其他技术对比2.4 SSE 的优缺点 3. 实战代码 1. 问题描述 目前做的一个功能是上传多个文件&#xff0c;这个上传文件是整体功能的一部分&#xff0c;文件在上传的过程中…...

02.运算符

目录 什么是运算符 算术运算符 1.基本四则运算符 2.增量运算符 3.自增/自减运算符 关系运算符 逻辑运算符 &&&#xff1a;逻辑与 ||&#xff1a;逻辑或 &#xff01;&#xff1a;逻辑非 短路求值 位运算符 按位与&&#xff1a; 按位或 | 按位取反~ …...

生产管理系统开发:专业软件开发公司的实践与思考

生产管理系统开发的关键点 在当前制造业智能化升级的转型背景下&#xff0c;生产管理系统开发正逐步成为企业优化生产流程的重要技术手段。不同行业、不同规模的企业在推进生产管理数字化转型过程中&#xff0c;面临的挑战存在显著差异。本文结合具体实践案例&#xff0c;分析…...