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

进程之间的通信(共享内存 + 其他IPC原理)

进程之间的通信(共享内存)

  • 1 共享内存
    • 1.1 共享内存原理
    • 1.2 预备知识
  • 3 (无保护)共享内存的代码示例
  • 4 共享内存的特点
  • 5 加保护的共享内存(管道保护)
  • 6 其他IPC
    • 6.1 system V消息队列(后序补充)
    • 6.2 system V信号量
  • 7 system v是如何实现IPC的?和滚到为什么不同?
    • 7.1 应用角度,IPC属性
    • 7.2 内核角度,看IPC结构

1 共享内存

1.1 共享内存原理

在这里插入图片描述

1、共享内存本质上就是物理内存上的一块区域,我们通过将其与页表建立链接,并映射到进程的共享区,这样我们的进程就能够看到这份资源,如果我们将另一个进程也与其建立链接,那么物理内存上的这块区域就叫做共享区。
2、共享内存本质上也是让不同的进程,看到同一份资源
3、当我们不需要使用共享区时,我们需要将物理内存区域与共享区去关联
4、共享内存可以有多个,其需要被OS管理(先描述,在组织)
5、共享内存 == 共享内存的数据结构 + 内存块

1.2 预备知识

1、共享内存也是由一个进程创建,另一个进程使用
2、man shmget(获取共享内存)

在这里插入图片描述

第一个参数:共享内存有唯一的标识符(key)
(1)必须用户输入
(2)怎么保证shm唯一性?怎么保证不同进程看到的是同一个共享内存?
---- 我们自己输入一个唯一的key,

第三个参数一般只使用两个(IPC_CREAT | IPC_EXCL)
(1)单独使用IPC_CREAT,如果shm不存在则创建,存在则获取它,并返回 ---- 保证能拿到共享内存
(2)单独使用IPC_EXCL,单独使用无意义
(3)两者共同使用,如果shm不存在,则创建,如果存在,出错返回 ---- 只要成功,一定是新的共享内存(不拿老的共享内存)

3、为什么key不由OS创建?而是用户传入?
如果key由OS创建了,另一个进程怎么拿到key?用户定义key才能使两个进程互相通信
4、我们设置key会不会发生冲突,发生冲突怎么办?
会发生冲突,发生时需要由用户手动更改,OS封装ftok(man ftok),由OS的算法形成唯一值

在这里插入图片描述

5、linux是通过路径+项目ID确定不同进程看到同一个资源
6、共享内存的生命周期随内核(必须手动释放 / OS重启),malloc出来的空间随进程,进程结束自动释放

共享内存的管理指令
(1)ipcs -m: 系统层面查看共享内存
(2)ipcrm -m + shmid:删除共享内存
(3)shmid:只给用户的一个标识shm的标识符
key:只作为内核中区分shm唯一性的标识符,不作为管理shm的id值

7、代码释放shm (man shmctl)

在这里插入图片描述

8、将共享内存挂接到自己的地址空间中

在这里插入图片描述

(1)shmaddr:由用户决定挂接到什么虚拟空间,在这里我们不需要关注,所以设置为nullptr即可
(2)shmflg:共享内存用来干什么,这里我们也不会用到,设置为0即可
(3)返回值void*:成功挂载时,返回虚拟地址的起始地址,失败则返回-1

9、去共享内存和进程地址空间的关联(shmdt)
参数就是挂接共享内存的返回值

3 (无保护)共享内存的代码示例

1、makefile
在这里插入图片描述
2、server.cc
在这里插入图片描述
3、client.cc
在这里插入图片描述
4、ShareMemory.hpp

#pragma once#include <iostream>
#include <string>
#include <cstdio>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <unistd.h>const std::string path = "/home/tsy/lesson";
int projId = 0x6666;
int gshmsize = 4096; // OS按照1k 4k 4m申请空间
mode_t gmode = 0600;std::string ToHex(key_t k)
{char buff[64];snprintf(buff, sizeof(buff), "0x%x", k);return buff;
}class ShareMemory
{void CreateShmHeaper(int shmflg){// 1、创建key_key = ::ftok(path.c_str(), projId);if (_key < 0){std::cerr << "ftok error!" << std::endl;return;}// 2、创建共享内存 && 获取// 注意:共享内存也有权限!shmflg_shmid = ::shmget(_key, gshmsize, shmflg);if (_shmid < 0){std::cerr << "shmget error!" << std::endl;return;}return;}public:ShareMemory() : _shmid(-1), _key(0), _addr(nullptr){}~ShareMemory() {}void CreateShm(){if (_shmid == -1)CreateShmHeaper(IPC_CREAT | IPC_EXCL | gmode); //|mode 给定共享内存权限}void GetShm(){CreateShmHeaper(IPC_CREAT);}void AttachShm(){// 3、共享内存挂接到自己的地址空间_addr = shmat(_shmid, nullptr, 0);if ((long long)_addr == -1){std::cout << "attach error" << std::endl;}}void DetachShm(){// 5、去关联地址空间if (_addr != nullptr)::shmdt(_addr);}void DeleteShm(){// 6、删除共享内存shmctl(_shmid, IPC_RMID, nullptr);}void *GetAddr(){return _addr;}void ShmMeta(){}private:int _shmid;key_t _key;void *_addr;
};ShareMemory shm;

共享内存不光可以传递字符串信息,图片、文件等结构化信息都是可以的

在这里插入图片描述

4 共享内存的特点

1、通信速度最快
2、让两个进程在各自的用户空间共享内存块,但是没有加任何保护机制
3、共享内存的保护机制需要用户完成保护(我们使用信号量 / 命名管道,锁我们没学),被保护的共享资源就是临界资源,访问公共资源的代码叫做临界区

5 加保护的共享内存(管道保护)

在这里插入图片描述

Fifo.hpp

#pragma once
#include <iostream>
#include <string>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>const std::string gpipeFile = "./fifo";
const mode_t gfifomode = 0600; // 设置权限
const int gdefaultfd = -1;
const int gsize = 1024;
const int gForRead = O_RDONLY;
const int gForWrite = O_WRONLY;class Fifo
{void OpenFifo(int flag){_fd = open(gpipeFile.c_str(), flag);if (_fd < 0){std::cerr << "open error" << std::endl;}}public:Fifo() : _fd(-1){umask(0);int n = ::mkfifo(gpipeFile.c_str(), gfifomode); // 创建管道文件if (n < 0){std::cerr << "mkfifo error" << std::endl;}std::cout << "mkfifo success" << std::endl;}bool OpenPipeForRead(){OpenFifo(gForRead);if (_fd < 0)return false;return true;}bool OpenPipeForWrite(){OpenFifo(gForWrite);if (_fd < 0)return false;return true;}int Wait(){int code = 0;ssize_t n = ::read(_fd, &code, sizeof(code)); // 可以读1024个字节,但是我们这里以字符形式读取,最后一个得补\0if (n == sizeof(code))return 0;else if (n == 0)return 1;elsereturn 2;}void Signal(){int code = 1;::write(_fd, &code, sizeof(code));}~Fifo(){if (_fd >= 0)::close(_fd);int n = unlink(gpipeFile.c_str()); // 删除管道文件if (n < 0){std::cout << "unlink error" << std::endl;return;}std::cout << "unlink success" << std::endl;}private:int _fd;
};Fifo gpipe;

Client.cc

在这里插入图片描述

server.cc

在这里插入图片描述

6 其他IPC

6.1 system V消息队列(后序补充)

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

6.2 system V信号量

在这里插入图片描述
nsems:信号量个数
1、临界区、临界代码
在这里插入图片描述

2、信号和信号量没有任何关系,不要混淆,信号量生命周期随内核
3、信号量本质是一个计算器
4、资源整体使用(互斥访问,临界区串行执行),将资源分开使用(不同进程的进程可以访问共享资源,具有一定并发性),为了防止过量进程进入临界资源,我们设置一个计数器cnt(cnt代表剩余资源的数目)

在这里插入图片描述

5、当cnt最大值为1时,就是将资源整体使用,所谓的cnt不光起到计算器的作用,更起到了资源预定的作用
6、信号量:对资源进行预定的计数器,资源整体使用的信号量就是二元信号量(锁)

计算器cnt是int型,能在多个进程之间被看到?被修改?
---- 不能,所以使用信号量这个计数器必须解决这个问题,假如多个进程之间能看到同一个计数器,那这个计数器本身就变为了公共资源,计数器怎么保证自己的安全?信号量的操作本质上只有两种(cnt–,cnt++),只要我们将这两种类型的操作打个包,包含cnt–的操作被称为P操作,包含cnt++的操作叫做V操作,只要保证这两种操作运行时不能被别人打断(原子性)

在这里插入图片描述

7、信号量可以为多个,system V申请信号量,是通过信号量集的方式申请的
8、信号量的操作(p / v)

在这里插入图片描述

7 system v是如何实现IPC的?和滚到为什么不同?

7.1 应用角度,IPC属性

在这里插入图片描述

在OS层面,IPC是同类
共享内存获取属性
在这里插入图片描述
代码获取共享内存的属性
在这里插入图片描述

7.2 内核角度,看IPC结构

1、IPC资源一定是全局资源,能被所有进程看到
2、


文章转载自:

http://VQVEJCVk.pqqhL.cn
http://7z7S3X7s.pqqhL.cn
http://maf5jiIV.pqqhL.cn
http://jXP9qW38.pqqhL.cn
http://wV1MKS4Z.pqqhL.cn
http://4AA36x6P.pqqhL.cn
http://jKw66cRQ.pqqhL.cn
http://MuqjuZR8.pqqhL.cn
http://0ccyldTb.pqqhL.cn
http://hstw1MxJ.pqqhL.cn
http://7LN3aLSs.pqqhL.cn
http://tBG7OFQo.pqqhL.cn
http://J6JTp8NW.pqqhL.cn
http://TCkvhmQ1.pqqhL.cn
http://kt0CBL0u.pqqhL.cn
http://HNd3Z2ig.pqqhL.cn
http://O5Cn7IqI.pqqhL.cn
http://RWACB3Br.pqqhL.cn
http://oo8yln48.pqqhL.cn
http://JIzYFD1V.pqqhL.cn
http://zPJZESon.pqqhL.cn
http://0sko3lnl.pqqhL.cn
http://AOvpmDi0.pqqhL.cn
http://hDxDVriN.pqqhL.cn
http://y6q8pHxw.pqqhL.cn
http://ectHeJOS.pqqhL.cn
http://uxOkfKwa.pqqhL.cn
http://dA75nUpp.pqqhL.cn
http://QE71UdGT.pqqhL.cn
http://9AkaJicZ.pqqhL.cn
http://www.dtcms.com/a/386466.html

相关文章:

  • AI 提示词学习笔记
  • PHP通过命令行调用Ghostscript把pdf转换成图片集
  • AWS 弹性伸缩(Auto Scaling)详解:服务器如何自动顶住流量洪峰?
  • 企业级AI应用落地实战(一):落地历程分享
  • 主数据管理:标准化缺失的潜在三大风险
  • LLC--开关损耗及软开关
  • 计算机视觉 - 对比学习(下)不用负样本 BYOL + SimSiam 融合Transformer MoCo-v3 + DINO
  • 内存与网络的字节序:大端 vs 小端
  • Linux网络:网络基础
  • [视图功能3] 排序与分组在业务数据分析中的应用
  • 架构师成长之路-集群
  • 《WINDOWS 环境下32位汇编语言程序设计》学习17章 PE文件(1)
  • cursor中配置qwen3-coder模型使用
  • 智慧健康驿站:AI与IoT赋能下的健康社区建设新引擎
  • 贪心算法应用:MEC任务卸载问题详解
  • Linux基础知识-安装jdk8与jmeter
  • 基于Django+Vue的新闻文本分类系统(协同过滤推荐算法)
  • 机器人控制器开发(通讯——建图和导航模式切换)
  • 容器化部署项目05
  • AI如何深度驱动数据资产入表业务开展-一线经验
  • Chromium 138 编译指南 macOS 篇:Xcode 与开发工具安装配置(二)
  • 网络.1 UDP
  • 在 Mac 环境安装全局默认版本 Python
  • 小迪安全v2023学习笔记(八十三讲)—— 组件安全JacksonFastJsonXStreamCVE复现
  • 鲁能大师显卡跑分计算规则,与算力对应关系?
  • 边缘智能的“隐形引擎”——TinyML 模型在 ARM Cortex-M 系列上的极致量化与加速实战
  • kernel32.dll如何修复?科普kernel32.dll缺失的故障问题的多种解决方法
  • git推送远程仓库
  • 「日拱一码」091 机器学习——集成学习
  • MTK Linux Charger驱动分析(五)- adapter_class.c