进程间通信(命名管道 共享内存)
文章目录
- 命名管道
- 原理
- 命令创建命名管道
- 函数创建命名管道
- 共享内存
- 原理
- shmget
- FIOK
- 代码应用:
- prems
- nattch
命名管道
用于两个毫无关系的进程间的通信。
原理
Linux文件的路径是多叉树,故文件的路径是唯一的。
让内核缓冲区不用刷新到磁盘中,一旦刷新就拖慢了操作系统。所以磁盘中有个特殊文件,在内存中写入不会刷新到磁盘,让两个进程在内存中通信,该文件叫做命名管道。(命名:有路径就有名字;管道:用于内存通信)
命令创建命名管道
可以直接使用系统命令创建命名管道
p打头的文件就是管道文件
echo是进程,cat也是进程。两个进程基于管道实现了通信。写入的时候,管道的大小依旧为0。
函数创建命名管道
返回值:成功返回0,失败返回-1
删除指定路径的文件:unlink
返回值:成功返回0,失败返回-1
代码如下:
client.cc 负责写:
#include "namedPipe.hpp"// client write
int main()
{NamePiped fifo(comm_path, User);if (fifo.OpenForWrite()){std::cout << "client open namd pipe done" << std::endl;while (true){std::cout << "Please Enter > ";std::string message;getline(std::cin, message);fifo.WriteNamedpipe(message);}}return 0;
}
namePipe.hpp:
#pragma once#include <iostream>
#include <cstdio>
#include <cerrno>
#include <string>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>const std::string comm_path = "./myfifo";//管道的名字
#define DefaultFd -1
#define Creater 1
#define User 2
#define Read O_RDONLY
#define Write O_WRONLY
#define BaseSize 4096//一次读多少字节class NamePiped
{
private:bool OpenNamedPipe(int mode)//权限{_fd = open(comm_path.c_str(),mode);if(_fd < 0)return false;return true;}
public:NamePiped(const std::string &path, int who) : _fifo_path(path), _id(who),_fd(DefaultFd){if (_id == Creater){int res = mkfifo(_fifo_path.c_str(), 0666);if (res != 0){perror("mkfifo");}std::cout << "Creater creat Named pipe" << std::endl;}}bool OpenForRead(){return OpenNamedPipe(Read);}bool OpenForWrite(){return OpenNamedPipe(Write);}int ReadNamedpipe(std::string *out){char buffer[BaseSize];int n = read(_fd,buffer,sizeof(buffer));if(n > 0){buffer[n] = 0;*out = buffer;}return n;}int WriteNamedpipe(const std::string &in){return write(_fd,in.c_str(),in.size());}~NamePiped(){if (_id == Creater){sleep(5);int res = unlink(_fifo_path.c_str());if (res != 0){perror("unlink");}std::cout << "Creater free Named pipe" << std::endl;}if(_fd != DefaultFd) close(_fd);}private:const std::string _fifo_path; //管道路径int _id; //身份(user/creater)int _fd; //文件描述符
};
server.cc 读端:
#include "namedPipe.hpp"// server read:管理命名管道的生命周期(创建与删除)
int main()
{NamePiped fifo(comm_path, Creater);if(fifo.OpenForRead()){std::cout << "server open named pipe done" << std::endl;while (true){std::string message;int res = fifo.ReadNamedpipe(&message);if (res > 0)//读内容{std::cout << "Client send >" << message << std::endl;}else if(res == 0)//写端关闭{std::cout << "Client quit" << std::endl;break;}else//出错{std::cout << "fifo.ReadNamedpipe default" << std::endl;break;}}}return 0;
}
运行:
光运行./server(读端),不运行写端会创建出管道,但读没有打印出server open named pipe done。说明没有打开管道。
然后运行了./client(写端)才会打开管道。说明对于读端而言,如果我们打开文件,但还没有写端,就会阻塞在open调用中,直到对方打开。简称进程同步。
相反如果读端关闭,写端还在写,写端就会收到SIGPIPE信号,让写端进程直接退出
共享内存
匿名管道和命名管道就是复用文件的代码。
有人从零开始写本地通信方案的代码:System V IPC 有三种方式通信
因为只能本地通信,且和文件的整合度不高,所以目前这种方案已经快被淘汰了。
原理
假设A进程在物理内存中创建一段内存空间,然后在A进程的地址空间中的共享区申请一片空间,再把虚拟地址与共享内存的映射关系填入页表。拥有映射关系后就可以往创建的内存中写入。B进程的虚拟地址也通过页表与创建的内存映射。这样进程A与进程B看到同一块资源,上面的技术叫做共享内存。
补充:
1.以上操作都是由操作系统做的,所以操作系统肯定提供给用户系统调用了。
2.AB进程通信,CD进程也要通信,所以共享进程在系统中可以存在很多份,且功能也不一样。操作系统就要对共享内存做管理!先描述,再组织。类似struct Shm的结构体。
综上所述:共享内存 = 共享内存空间(数据) + 共享内存属性
shmget
创建共享内存的函数调用:IPC_CREAT用于获取;IPC_CREAT | IPC_EXCL用于创建。
key比较特殊,是标识共享内存的唯一性字段,用于寻找共享空间。
综上:用户设置key值,AB两个进程就能看见同一块共享空间。
key值是给用户看的,后面会说shmid是给操作系统看的,所以操作系统不创建key值。
但是又不建议用户自己设置key,容易冲突,就给用户提供了函数ftok,由一些算法形成的随机数。
FIOK
同一个pathname,同一个proj_id,就能由算法形成同一个key。
返回值:成功后返回的是key的值;失败后返回-1
代码应用:
先验证共享内存的几个特性:
共享内存,不随着进程的结束释放。
Shm.hpp
#ifndef __SHM_HPP__
#define __SHM_HPP__#include <iostream>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <cerrno>#define gShmSize 4096const std::string gpathname = "/root/test/shm";
const int gproj_id = 0x66;std::string ToHex(key_t k)
{char buffer[128];snprintf(buffer,sizeof(buffer),"0x%x",k);return buffer;
}key_t GetCommKey(const std::string pathname, int proj_id)
{key_t res = ftok(pathname.c_str(), proj_id);if (res < 0){perror("create ftok failing");}return res;
}int GetShm(int key)
{int shmid = shmget(key,gShmSize,IPC_CREAT | IPC_EXCL);if(shmid < 0){perror("shmget fail");}return shmid;
}#endif
server.cc
#include "Shm.hpp"int main()
{key_t k = GetCommKey(gpathname,gproj_id);std::cout << "key: " << ToHex(k) << std::endl;int shmid = GetShm(k);std::cout << "shmid:" << shmid << std::endl;return 0;
}
运行两次,发现第二次并没有创建,并显示已经存在,说明共享内存并没有像子进程一样运行完就被父进程或系统回收。
把创建共享内存改成获取共享内存:
int GetShm(int key)
{int shmid = shmget(key,gShmSize,IPC_CREAT);if(shmid < 0){perror("shmget fail");}return shmid;
}
发现获取的话可以一直获取。
如果不释放共享内存,就会一直存在,生命周期随内核。
查共享内存:
ipcs -m
key:属于用户形成,内核使用的一个字段,用户不能使用key来进行shm管理。
shmid:内核给用户返回的一个标识符,用来进行用户级对共享内存进行管理的id值。
删共享内存用命令shmid删除:
ipcrm -m [shmid]
也可以用操作系统提供的函数:shmctl删除。cmd删除是IPC_RMID,就是位图。
返回值:移植成功,返回0;失败,返回-1
综上所述:创建共享内存,使用后删除的代码就能写出来了:
#ifndef __SHM_HPP__
#define __SHM_HPP__#include <iostream>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <unistd.h>
#include <cerrno>#define gCreater 1
#define gUser 2
#define gShmSize 4096const std::string gpathname = "/root/test/shm";
const int gproj_id = 0x66;class Shm
{
private:key_t GetCommKey(){key_t key = ftok(_pathname.c_str(), _proj_id);if (key < 0){perror("create ftok failing");}return key;}int GetShmHelper(key_t key, int size, int flag){int shmid = shmget(key, size, flag);if (shmid < 0){perror("shmget fail");}return shmid;}public:Shm(const std::string pathname, const int proj_id, int who): _pathname(pathname), _proj_id(proj_id), _who(who){_key = GetCommKey();if (_who == gCreater){CreaterGetShmid();}else if (_who == gUser){UserGetShmid();}std::cout << "shmid: " << _shmid << std::endl;std::cout << "key: " << ToHex(_key) << std::endl;}~Shm(){if (_who == gCreater){int res = shmctl(_shmid, IPC_RMID, nullptr);if (res < 0)std::cout << "shmctl fail " << std::endl;elsestd::cout << "shmid remove done " << std::endl;}}std::string ToHex(key_t k){char buffer[128];snprintf(buffer, sizeof(buffer), "0x%x", k);return buffer;}bool CreaterGetShmid(){if (_who == gCreater){_shmid = GetShmHelper(_key, gShmSize, IPC_CREAT | IPC_EXCL);sleep(10); //为了创建完看见删除的效果if (_shmid > 0)return true;}std::cout << "Create shmid succeed" << std::endl;return false;}bool UserGetShmid(){if (_who == gUser){_shmid = GetShmHelper(_key, gShmSize, IPC_CREAT);if (_shmid > 0)return true;}std::cout << "Get shmid succeed" << std::endl;return false;}private:key_t _key;int _shmid;int _who;const std::string _pathname;const int _proj_id;
};#endif
创建出共享内存后10秒钟后删除
prems
perms是共享内存的权限:如果创建的时候,加上权限,perms的值会更改。
bool CreaterGetShmid(){if (_who == gCreater){_shmid = GetShmHelper(_key, gShmSize, IPC_CREAT | IPC_EXCL | 0666);if (_shmid > 0)return true;}std::cout << "Create shmid succeed" << std::endl;return false;}
nattch
nattch是该共享内存挂接的数量。
挂接的函数:shmat(at有attach的意思)
返回值:一旦挂接成功,返回地址空间中共享内存的起始地址。(跟malloc返回值类似)
挂接代码:
std::string RoleToString(int who){if (who == gCreater)return "Creater";else if (who == gUser)return "gUser";elsereturn "None";}// 挂接void *AttachShm(){void *shmaddr = shmat(_shmid, nullptr, 0);if (shmaddr == nullptr){perror("shmat");}std::cout << "who: " << RoleToString(_who) << " attach shm..." << std::endl;return shmaddr;}
一个进程挂接上了为1,两个进程挂接上了为2。
去掉进程与共享内存的关联的函数:shmdt
代码如下:
void DetachShm(void *shmaddr){if(shmaddr == nullptr) return;shmdt(shmaddr);std::cout << "who: " << RoleToString(_who) << " detach shm..." << std::endl;}
效果:0-》1-》0
上面都是准备工作:下面开始通信。
只运行读端:
现象:发现不等写端写入,读端一直在读。
读端和写端都运行:
现象:写端2秒写一次,读端1秒读1次,数据就有重复。(相比较通道读完数据就没有了)
读端和写端都运行,然后把写端关闭后再次运行写端:
现象:读端重新读取
综上所述:与管道不一样,共享内存不提供保护机制。
缺点:会造成数据不一致问题(在纸上写字,写一半被别人拿走了)
优点:共享内存收所有进程IPC,速度最快的。因为共享内存大大减少了数据的拷贝次数。
相关文章:

进程间通信(命名管道 共享内存)
文章目录 命名管道原理命令创建命名管道函数创建命名管道 共享内存原理shmgetFIOK 代码应用:premsnattch 命名管道 用于两个毫无关系的进程间的通信。 原理 Linux文件的路径是多叉树,故文件的路径是唯一的。 让内核缓冲区不用刷新到磁盘中,…...

Python 网络爬虫教程:从入门到高级的全面指南
Python 网络爬虫教程:从入门到高级的全面指南 引言 在信息爆炸的时代,网络爬虫(Web Scraping)成为了获取数据的重要工具。Python 以其简单易用的特性,成为了网络爬虫开发的首选语言。本文将详细介绍如何使用 Python …...
深度学习:正则化(Regularization)详细解释
正则化(Regularization)详细解释 正则化(Regularization)是机器学习和统计建模领域中用以防止模型过拟合同时增强模型泛化能力的一种技术。通过引入额外的约束或惩罚项到模型的损失函数中,正则化能够有效地限制模型的…...

Freertos学习日志(1)-基础知识
目录 1.什么是Freertos? 2.为什么要学习RTOS? 3.Freertos多任务处理的原理 1.什么是Freertos? RTOS,即(Real Time Operating System 实时操作系统),是一种体积小巧、确定性强的计算机操作系统…...

CentOS9 Stream 支持输入中文
CentOS9 Stream 支持输入中文 方法一:确保 gnome-control-center 和相关组件已更新方法二:手动添加输入法源配置方法三:配置 .xinputrc 文件方法四:检查语言包 进入centos9 stream后,点击右上角电源键,点击…...

基于向量检索的RAG大模型
一、什么是向量 向量是一种有大小和方向的数学对象。它可以表示为从一个点到另一个点的有向线段。例如,二维空间中的向量可以表示为 (𝑥,𝑦) ,表示从原点 (0,0)到点 (𝑥,𝑦)的有向线段。 1.1、文本向量 1…...
【力扣 + 牛客 | SQL题 | 每日5题】牛客SQL热题216,217,223
也在牛客力扣写了一百来题了,个人感觉力扣的SQL题要比牛客的高三档的难度。(普遍来说) 1. 牛客SQL热题216:统计各个部门的工资记录数 1.1 题目: 描述 有一个部门表departments简况如下: dept_nodept_named001Marke…...

Unity humanoid 模型头发动画失效问题
在上一篇【Unity实战笔记】第二十二 提到humanoid 模型会使原先的头发动画失效,如下图所示: 头发摆动的是generic模型和动画,不动的是humanoid模型和动画 一开始我是尝试过在模型Optimize Game objects手动添加缺失的头发骨骼的,奈…...

最全Kafka知识宝典之Kafka的基本使用
一、基本概念 传统上定义是一个分布式的基于发布/订阅模式的消息队列,主要应用在大数据实时处理场景,现在Kafka已经定义为一个分布式流平台,用于数据通道处理,数据流分析,数据集成和关键任务应用 必须了解的四个特性…...

机器学习中的数据可视化:常用库、单变量图与多变量图绘制方法
《博主简介》 小伙伴们好,我是阿旭。专注于人工智能、AIGC、python、计算机视觉相关分享研究。 ✌更多学习资源,可关注公-仲-hao:【阿旭算法与机器学习】,共同学习交流~ 👍感谢小伙伴们点赞、关注! 《------往期经典推…...

CodeQL学习笔记(3)-QL语法(模块、变量、表达式、公式和注解)
最近在学习CodeQL,对于CodeQL就不介绍了,目前网上一搜一大把。本系列是学习CodeQL的个人学习笔记,根据个人知识库笔记修改整理而来的,分享出来共同学习。个人觉得QL的语法比较反人类,至少与目前主流的这些OOP语言相比&…...
代码随想录训练营Day11 | 226.翻转二叉树 - 101. 对称二叉树 - 104.二叉树的最大深度 - 111.二叉树的最小深度
226.翻转二叉树 题目链接:226.翻转二叉树思路:遍历二叉树,遍历的时候交换左右节点即可代码: TreeNode* invertTree(TreeNode* root) {reverse(root);return root;}// 迭代法,层序遍历void f2(TreeNode* root) {queue…...

“死鱼眼”,不存在的,一个提词小技巧,拯救的眼神——将内容说给用户,而非读给用户!
视频录制时,死鱼眼问题常见 即便内容再好,眼神死板也会减分 痛点真痛:拍视频时容易紧张 面对镜头,许多人难免紧张 神情僵硬,眼神无光,甚至忘词 这不仅影响表现,还让人难以专注 忘我场景&#x…...

深度学习在复杂系统中的应用
引言 复杂系统由多个相互作用的组成部分构成,这些部分之间的关系往往是非线性的,整体行为难以通过简单的线性组合来预测。这类系统广泛存在于生态学、气象学、经济学和社会科学等多个领域,具有动态演变、自组织、涌现现象以及多尺度与异质性…...
vue3图片懒加载
背景 界面很长,屏幕不能一下装下所有内容,如果以进入首页就把所有内容都加载完的话所需时间较长,会影响用户体验,所以可以当用户浏览到时再去加载。 代码 新建index.ts文件 src下新建directives文件夹,并新建Index…...
总结一些高级的SQL技巧
1. 窗口函数 窗函数允许在查询结果的每一行上进行计算,而不需要将数据分组。这使得我们可以计算累积总和、排名等。 SELECT employee_id,salary,RANK() OVER (ORDER BY salary DESC) AS salary_rank FROM employees;2. 公用表表达式 (CTE) CTE 提供了一种更清晰的…...

无人机飞手考证热,装调检修技术详解
随着无人机技术的飞速发展和广泛应用,无人机飞手考证热正在持续升温。无人机飞手不仅需要掌握飞行技能,还需要具备装调检修技术,以确保无人机的安全、稳定和高效运行。以下是对无人机飞手考证及装调检修技术的详细解析: 一、无人机…...

AI资讯快报(2024.10.27-11.01)
1.<国家超级计算济南中心发布系列大模型> 10月28日,以“人才引领创新 开放赋能发展”为主题的第三届山东人才创新发展大会暨第十三届“海洽会”集中展示大会在山东济南举行。本次大会发布了国家超级计算济南中心大模型,包括“智匠工业大模型、知风…...

范式的简单理解
第二范式 消除非键属性对键的部分依赖 第三范式 消除一个非键属性对另一个非键属性的依赖 表中的每个非键属性都应该依赖于键,整个键,而且只有键(键可能为两个属性) 第四范式 多值依赖于主键...
活着就好20241103
🌞 早晨问候:亲爱的朋友们,大家早上好!今天是2024年11月3日,第44周的第七天,也是本周的最后一天,农历甲辰[龙]年十月初三。在这金秋十一月的第三天,愿清晨的第一缕阳光如同活力的源泉…...
C++:std::is_convertible
C++标志库中提供is_convertible,可以测试一种类型是否可以转换为另一只类型: template <class From, class To> struct is_convertible; 使用举例: #include <iostream> #include <string>using namespace std;struct A { }; struct B : A { };int main…...

VB.net复制Ntag213卡写入UID
本示例使用的发卡器:https://item.taobao.com/item.htm?ftt&id615391857885 一、读取旧Ntag卡的UID和数据 Private Sub Button15_Click(sender As Object, e As EventArgs) Handles Button15.Click轻松读卡技术支持:网站:Dim i, j As IntegerDim cardidhex, …...

visual studio 2022更改主题为深色
visual studio 2022更改主题为深色 点击visual studio 上方的 工具-> 选项 在选项窗口中,选择 环境 -> 常规 ,将其中的颜色主题改成深色 点击确定,更改完成...
蓝桥杯 2024 15届国赛 A组 儿童节快乐
P10576 [蓝桥杯 2024 国 A] 儿童节快乐 题目描述 五彩斑斓的气球在蓝天下悠然飘荡,轻快的音乐在耳边持续回荡,小朋友们手牵着手一同畅快欢笑。在这样一片安乐祥和的氛围下,六一来了。 今天是六一儿童节,小蓝老师为了让大家在节…...
测试markdown--肇兴
day1: 1、去程:7:04 --11:32高铁 高铁右转上售票大厅2楼,穿过候车厅下一楼,上大巴车 ¥10/人 **2、到达:**12点多到达寨子,买门票,美团/抖音:¥78人 3、中饭&a…...
渲染学进阶内容——模型
最近在写模组的时候发现渲染器里面离不开模型的定义,在渲染的第二篇文章中简单的讲解了一下关于模型部分的内容,其实不管是方块还是方块实体,都离不开模型的内容 🧱 一、CubeListBuilder 功能解析 CubeListBuilder 是 Minecraft Java 版模型系统的核心构建器,用于动态创…...

linux arm系统烧录
1、打开瑞芯微程序 2、按住linux arm 的 recover按键 插入电源 3、当瑞芯微检测到有设备 4、松开recover按键 5、选择升级固件 6、点击固件选择本地刷机的linux arm 镜像 7、点击升级 (忘了有没有这步了 估计有) 刷机程序 和 镜像 就不提供了。要刷的时…...
Qt Http Server模块功能及架构
Qt Http Server 是 Qt 6.0 中引入的一个新模块,它提供了一个轻量级的 HTTP 服务器实现,主要用于构建基于 HTTP 的应用程序和服务。 功能介绍: 主要功能 HTTP服务器功能: 支持 HTTP/1.1 协议 简单的请求/响应处理模型 支持 GET…...

技术栈RabbitMq的介绍和使用
目录 1. 什么是消息队列?2. 消息队列的优点3. RabbitMQ 消息队列概述4. RabbitMQ 安装5. Exchange 四种类型5.1 direct 精准匹配5.2 fanout 广播5.3 topic 正则匹配 6. RabbitMQ 队列模式6.1 简单队列模式6.2 工作队列模式6.3 发布/订阅模式6.4 路由模式6.5 主题模式…...

推荐 github 项目:GeminiImageApp(图片生成方向,可以做一定的素材)
推荐 github 项目:GeminiImageApp(图片生成方向,可以做一定的素材) 这个项目能干嘛? 使用 gemini 2.0 的 api 和 google 其他的 api 来做衍生处理 简化和优化了文生图和图生图的行为(我的最主要) 并且有一些目标检测和切割(我用不到) 视频和 imagefx 因为没 a…...