进程间通信I·匿名管道
目录
进程间通信(IPC)
含义
目的
分类
匿名管道
原理
创建过程
特性
四大情况
close问题
代码练习
简单通信
进程池
小知识
进程间通信(IPC)
含义
就是让不同的进程能看到同一份资源,实现数据交流。
目的
1.数据传输:一个进程需要将它的数据发送给另一个进程
2.资源共享:多个进程之间共享同样的资源
3.通知事件:一个进程需要向另一个或一组进程发送消息,通知它(它们)发生了某种事件(如进程终止时要通知父进程)
4.进程控制:有些进程希望完全控制另一个进程的执行(如Debug进程),此时控制进程希望能够拦截另一个进程的所有陷入和异常,并且能够及时知道它的状态改变
分类
主要分三大类
1.管道:基于文件的通信方法,一般为单向通信的信道。
- 匿名管道
- 命名管道
2.System V IPC :操作系统中单独设计的通信模块(只能进行本地通信)
- System V 消息队列
- System V 共享内存
- System V 信号量
3.POSIX IPC:网络间进程通信
- 消息队列
- 共享内存
- 信号量
- 互斥量
- 条件变量
- 读写锁
匿名管道
原理
fork子进程时,PCB要拷贝,关联的文件的struct file结构体也会拷贝,父子进程的struct file通过自己的文件读写位置区访问文件属性和内容;为了保证父子读写不会冲突(同一个文件读写位置只有一个),所以要么父进程读,子进程写,要么子进程读,父进程写,这里父子进程就可以看到同一份资源了,这就是管道的原理。
创建过程
父进程以读写两种方式打开同一个管道文件,然后父进程创建子进程,子进程继承父进程,最后父进程和子进程关闭自己不需要的读或写方式。
1.父进程为什么以读写方式打开:为了让子进程也继承读写。
2.为什么关闭读写端:管道是单向通信的。
3.为什么单向通信:就是这样设计的。
pipe :创建匿名管道的系统调用
1.pipifd是输出型参数,会将创建的读写方式对应的文件描述符放到这个数组里,[0]为读,[1]为写。
2.成功返回0,失败返回-1,同时
errno
变量会被设置为相应的错误码,以指示具体的错误原因。
创建之后我们可以得知,匿名管道不存在文件名和路径,就不存在向磁盘中刷新数据,是由操作系统进行开辟和管理的内核中的一块缓冲区,是一个内存级的基于文件系统的文件。
特性
1.用于有血缘关系这样的进程进行进程通信(IPC)
2.单向通信
3.管道的生命周期随进程
4.面向字节流
5.管道自带同步机制
四大情况
1.写端不关,写端不写 管道里没有数据,读端会被阻塞(造就同步机制)
2.读端不关,读端不读 写满了(64kb,65536字节)就不会再写了
3.读端不关,写端先关 读端返回值会为0,表示读到文件结尾
4.写端不关,读端先关 OS会自动杀掉写进程,通过发送13号信号
close问题
如果多个子进程继承同一父进程时,在第一个之后的子进程会将父进程与之前的子进程建立的写端(读端)的fd也继承,让其引用计数++,这样如果最后按顺序进行close(fd)+wait 的话,是会出问题的。
例:父进程写,子进程读,创建第一个子进程时,父进程使用文件描述符表中3/4作为读端和写端,第一个子进程继承到3/4,然后父进程关闭3,子进程关闭4;接下来创建第二个子进程,父进程pipe会以3/5作为读端/写端,这时子进程继承,4也会被继承,这样这个子进程也就即指向了之前的管道,又指向它的管道,创建之后的子进程同理。
这样越先创建的管道,指向它的就越多,引用计数就越大,当父进程退出不写后,指向管道的写端的引用计数不为0,子进程认为仍有写端可以进行写,不会关闭。
解决方法:1.倒着关闭
2.在子进程创建时关闭之前子进程的继承来的fd。
代码练习
简单通信
main.cpp
#include "together.hpp"
int main()
{
int pipefd[2] = {0};
int piperet = pipe(pipefd);
if(piperet<0)
{
ERR_EXIT("pipe");
}
pid_t pid = fork();
if(pid<0)
{
ERR_EXIT("fork");
}
else if(pid==0)
{
close(pipefd[1]);
char buff[1024] = {'\0'};
while(1)
{
ssize_t readret = read(pipefd[0],buff,sizeof(buff)-1);
if(readret<0)
{
ERR_EXIT("read");
}
else if(readret==0)
{
cout<<"写端下班,我也下班喽"<<endl;
break;
}
else
{
buff[readret] = '\0';
cout<<"父进程说:"<<buff<<endl;
}
}
exit(0);
}
close(pipefd[0]);
ssize_t writeret = write(pipefd[1],"i am father",11);
sleep(2);
return 0;
}
together.hpp
#pragma once
#include <iostream>
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
using namespace std;
#define ERR_EXIT(s)\
do{\
perror(s);\
exit(EXIT_FAILURE);\
}while(0)
Makefile
ano_pipe:main.cpp
g++ -o $@ $^ -std=c++11
.PHONY:clean
clean:
rm -f ano_pipe
进程池
main.cpp
#include "pro_pool.hpp"
#define NUM 3
int main()
{
srand(time(nullptr));
//创建进程池
ProPool pool;
//初始化进程池
pool.InitProPool(NUM,[](int fd){
while(true)
{
int code = 0;
ssize_t n = read(fd,&code,sizeof(code));
if(n==sizeof(code))
{
if(code>=0&&code<NUM)
{
_task._t[code]();
}
else
{
std::cout<<"任务码错误 "<<code<<std::endl;
}
}
else if(n==0)
{
std::cout<<"子进程"<<getpid()<<"退出"<<std::endl;
break;
}
else
{
std::cout<<"read error"<<std::endl;
break;
}
}
});
//唤醒进程池
pool.Awake_Pro();
//结束进程池
pool.WaitPro();
return 0;
}
Makefile
pro_pool:main.cpp
g++ -o $@ $^ -std=c++11
.PHOMY:
clean:
rm -rf pro_pool
pro_pool.hpp
#ifndef PRO_POOL_HPP
#define PRO_POOL_HPP
#include <iostream>
#include <string>
#include <vector>
#include <functional>
#include <cstdio>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <time.h>
#include "task.hpp"
using namespace std;
using func_t = std::function<void(int fd)>;
Task_ _task;
class Channel
{
int _wfd;
std::string _name;
pid_t _pid;
public:
Channel() {}
Channel(int wfd, const std::string &name, pid_t pid) : _wfd(wfd), _name(name), _pid(pid) {}
~Channel() {}
int FD() { return _wfd; }
std::string Name() { return _name; }
pid_t Pid() { return _pid; }
void Close() { close(_wfd); }
void Wait()
{
pid_t ret = waitpid(_pid, nullptr, 0);
(void)ret;
}
};
class ProPool
{
std::vector<Channel> _channels;
int _progressnum = 0;
public:
ProPool() {}
~ProPool() {}
void InitProPool(int num, func_t cb)
{
_progressnum = num;
for (int i = 0; i < num; ++i)
{
int fdnum[2];
int ret = pipe(fdnum);
if (ret < 0)
exit(2);
pid_t pid = fork();
if (pid < 0)
exit(1);
else if (pid == 0)
{
close(fdnum[1]);
// 子进程执行任务
cb(fdnum[0]);
exit(0);
}
close(fdnum[0]);
std::string task_name = "channel " + to_string(i);
_channels.emplace_back(fdnum[1], task_name, pid);
}
}
void Awake_Pro()
{
for (int index = 0;; index++)
{
index %= _channels.size();
int code = rand() % _task.size();
std::cout << "唤醒" << _channels[index].Name() << std::endl;
ssize_t ret = write(_channels[index].FD(), &code, sizeof(code));
sleep(1);
}
}
void WaitPro()
{
while (_progressnum--)
{
_channels[_progressnum].Close();
_channels[_progressnum].Wait();
}
}
};
#endif
task.hpp
#include <iostream>
#include <vector>
#include <functional>
using namespace std;
using task_f = std::function<void ()>;
void download()
{
std::cout<<"download ing..."<<std::endl;
}
void unload()
{
std::cout<<"unload ing..."<<std::endl;
}
void run_childtask()
{
std::cout<<"run_childtask ing..."<<std::endl;
}
class Task_
{
public:
std::vector<task_f> _t;
Task_()
{
_t.push_back(download);
_t.push_back(unload);
_t.push_back(run_childtask);
}
size_t size(){return _t.size();}
};
小知识
1.C++中, .cpp .cxx .cc 都可以作为源文件的后缀 .hpp是头源结合,不过在编译时会被编译器当做头文件处理,所以单独的.hpp文件是不能形成正确的.exe的。
2.头文件的本质是函数和变量的声明的文本集合
相关文章:

进程间通信I·匿名管道
目录 进程间通信(IPC) 含义 目的 分类 匿名管道 原理 创建过程 特性 四大情况 close问题 代码练习 简单通信 进程池 小知识 进程间通信(IPC) 含义 就是让不同的进程能看到同一份资源,实现数据交流。 …...

Ubuntu Linux系统的基本命令详情
1.Ubuntu Linux是以桌面应用为主的Linux发行版操作系统 2.Ubuntu的用户使用 在登录系统一般使用在安装系统时建立的普通用户登录,如果要使用超级用户权限 #sudo ---执行命令 sudo passwd ---修改用户密码 su - root ---切换超级用户 系统的不同,命令也不…...

大数据治理:理论、实践与未来展望(二)
书接上文 文章目录 七、大数据治理的未来发展趋势(一)智能化与自动化(二)数据隐私与安全的强化(三)数据治理的云化(四)数据治理的跨行业合作(五)数据治理的生…...

PCB布局设计
PCB布局设计 一、原理图到PCB转换前的准备工作 在将原理图转换为PCB之前,我们需要进行一系列准备工作,确保设计的正确性和完整性。这一步骤至关重要,可以避免后续PCB设计中出现不必要的错误。 // 原理图转PCB前必要检查步骤 // 1. 仔细检查…...
【49. 字母异位词分组】
Leetcode算法练习 笔记记录 49. 字母异位词分组 49. 字母异位词分组 public List<List<String>> groupAnagrams(String[] strs) {Map<String, List<String>> map new HashMap<>();for (int i 0; i < strs.length; i) {//排序就是相同字符了…...
用 AI 让学习更懂你:如何打造自动化个性化学习系统?
用 AI 让学习更懂你:如何打造自动化个性化学习系统? 在这个信息爆炸的时代,传统的学习方式已经难以满足个体化需求。过去,我们依赖固定的教学课程,所有学生按照统一进度进行学习,但每个人的学习节奏、兴趣点和理解方式都不尽相同。而人工智能(AI)正在彻底改变这一局面…...

esp32+IDF V5.1.1版本编译freertos报错
error: portTICK_RATE_MS undeclared (first use in this function); did you mean portTICK_PERIOD_MS 解决方法: 使用命令 idf.py menuconfig 打开配置界面配置freeRtos 使能configENABLE_BACKWARD_COMPATIBLITY...
嵌入式软件-如何做好一份技术文档?
嵌入式软件-如何做好一份技术文档? 文章目录 嵌入式软件-如何做好一份技术文档?一.技术文档的核心价值与挑战二.文档体系的结构化设计三.精准表达嵌入式特有概念四. **像管理代码一样管理文档**,代码与文档的协同维护五.质量评估与持续改进5.…...

笔记本6GB本地可跑的图生视频项目(FramePack)
文章目录 (一)简介(二)本地执行(2.1)下载(2.2)更新(2.3)运行(2.4)生成 (三)注意(3.1)效…...

SpringMVC实战:动态时钟
引言 在现代 Web 开发中,选择一个合适的框架对于项目的成功至关重要。Spring MVC 作为 Spring 框架的核心模块之一,以其清晰的架构、强大的功能和高度的可配置性,成为了 Java Web 开发领域的主流选择。本文将通过一个“动态时钟”的实战项目…...
vscode include总是报错
VSCode 的 C/C 扩展可以通过配置 c_cpp_properties.json 来使用 compile_commands.json 文件中的编译信息,包括 include path、编译选项等。这样可以确保 VSCode 的 IntelliSense 与实际编译环境保持一致。 方法一:直接指定 compile_commands.json 路径…...

哈希表的实现(上)
前言 在C98中,STL提供了底层为红黑树结构的一系列关联式容器,在查询时效率可达到,即最差情况下需要比较红黑树的高度次,当树中的节点非常多时,查询效率也不理想。最好的查询是,进行很少的比较次数就能够将…...

【Java高阶面经:微服务篇】1.微服务架构核心:服务注册与发现之AP vs CP选型全攻略
一、CAP理论在服务注册与发现中的落地实践 1.1 CAP三要素的技术权衡 要素AP模型实现CP模型实现一致性最终一致性(Eureka通过异步复制实现)强一致性(ZooKeeper通过ZAB协议保证)可用性服务节点可独立响应(支持分区存活)分区期间无法保证写操作(需多数节点可用)分区容错性…...

实验7 HTTP协议分析与测量
实验7 HTTP协议分析与测量 1、实验目的 了解HTTP协议及其报文结构 了解HTTP操作过程:TCP三次握手、请求和响应交互 掌握基于tcpdump和wireshark软件进行HTTP数据包抓取和分析技术 2、实验环境 硬件要求:阿里云云主机ECS 一台。 软件要求࿱…...

python:机器学习概述
本文目录: 一、人工智能三大概念二、学习方式三、人工智能发展史**1950-1970****1980-2000****2010-2017****2017-至今** 四、机器学习三要素五、常见术语六、数据集的划分七、常见算法分类八、机器学习的建模流程九、特征工程特征工程包括**五大步**:特…...
【一. Java基础:注释、变量与数据类型详解】
1. Java 基础概念 1.1 注释 注释:对代码的解释和说明文字 java的三种注释: 单行注释:两个斜杠 // 后面跟着你的注释内容 //哈哈多行注释:以 /* 开头,以 */ 结尾,中间可以写很多行 /*哈哈哈哈哈哈…...

得力DE-620K针式打印机打印速度不能调节维修一例
基本参数: 产品类型 票据针式打印机(平推式) 打印方式 串行点阵击打式 打印宽度 85列 打印针数 24针 可靠性 4亿次/针 色带性能 1000万字符纠错 复写能力 7份(1份原件+6份拷贝) 缓冲区 128KB 接口类型 …...
SAP在金属行业的数字化转型:无锡哲讯科技的智能解决方案
金属行业面临的发展挑战 金属行业作为制造业的基础支柱,涵盖钢铁、有色金属、金属制品等多个细分领域。当前行业正面临原材料价格波动、能耗双控政策、市场竞争加剧等多重压力。数字化转型已成为金属企业提升生产效率、优化供应链、实现绿色可持续发展的必由之路。…...
安装openresty使用nginx+lua,openresty使用jwt解密
yum install -y epel-release yum update yum search openresty # 查看是否有可用包 yum install -y openresty启动systemctl start openresty验证服务状态systemctl status openresty设置开机自启systemctl enable openrestysystemctl stop openresty # 停止服务 system…...

java基础(继承)
什么是继承 继承好处 提高代码的复用性 继承注意事项 权限修饰符 单继承、Object类 冲突: 方法重写 扩展: 其实我们不想看地址,地址看来没用,我们是用来看对象有没有问题 重写toString: 比如这个如果返回的是地址值,…...
python 实现一个完整的基于Python的多视角三维重建系统,包含特征提取与匹配、相机位姿估计、三维重建、优化和可视化等功能
多视角三维重建系统 下面我将实现一个完整的基于Python的多视角三维重建系统,包含特征提取与匹配、相机位姿估计、三维重建、优化和可视化等功能。 1. 环境准备与数据加载 首先安装必要的库: pip install opencv-python opencv-contrib-python numpy…...
行列式中某一行的元素与另一行对应元素的代数余子式乘积之和等于零
问题陈述 为什么行列式中某一行(列)的元素与另一行(列)对应元素的代数余子式乘积之和等于零?即: ∑ k 1 n a i k C j k 0 ( i ≠ j ) \sum_{k1}^{n} a_{ik} C_{jk} 0 \quad (i \ne j) k1∑naikCjk…...
【时时三省】Python 语言----字符串,列表,元组,字典常用操作异同点
目录 1,字符串常用操作 1,创建 2,访问 3,常用方法 4,内置方法 2,列表 1,创建列表 2,访问列表 3,内置方法 3,元组 1,创建 2,访问 3,内置方法 4,字典 1,创建 2,访问 3,内置方法 5,集合 1,创建 2,访问 3,内置方法 山不在高,有仙则名。水不在深,有龙则…...

基于cornerstone3D的dicom影像浏览器 第二十二章 mpr + vr
系列文章目录 第一章 下载源码 运行cornerstone3D example 第二章 修改示例crosshairs的图像源 第三章 vitevue3cornerstonejs项目创建 第四章 加载本地文件夹中的dicom文件并归档 第五章 dicom文件生成png,显示检查栏,序列栏 第六章 stack viewport 显…...
优启通添加自定义浏览器及EXLOAD使用技巧分享
文章目录 优启通添加自定义浏览器及EXLOAD使用技巧分享🚩问题描述🔧解决方案概述📁自定义软件添加方法汇总🧩快捷方式配置:exload.cfg 用法大全🧷基础用法🗂分类菜单🖥创建桌面快捷方…...

MySQL:游标 cursor 句柄
当我们select * from emp 可以查看所有的数据 这个数据就相当于一个数据表 游标的作用相当于一个索引 一个指针 指向每一个数据 假设说我要取出员工中薪资最高的前五名成员 就要用到limit关键字 但是这样太麻烦了 所以这里用到了游标 游标的声明: declare my…...

二、ZooKeeper 集群部署搭建
作者:IvanCodes 日期:2025年5月24日 专栏:Zookeeper教程 我们这次教程将以 hadoop01 (192.168.121.131), hadoop02 (192.168.121.132), hadoop03 (192.168.121.133) 三台Linux服务器为例,搭建一个ZooKeeper 3.8.4集群。 一、下载…...

<< C程序设计语言第2版 >> 练习1-14 打印输入中各个字符出现频度的直方图
1. 前言 本篇文章是<< C程序设计语言第2版 >> 的第1章的编程练习1-14, 个人觉得还有点意思, 所以写一篇文章来记录下. 希望可以给初学C的同学一点参考. 尤其是自学的同学, 或者觉得以前学得不好, 需要自己补充学习的同学. 和我的很多其它文章一样, 不建议自己还没实…...

黑马点评双拦截器和Threadlocal实现原理
文章目录 双拦截器ThreadLocal实现原理 双拦截器 实现登录状态刷新的原因: 防止用户会话过期:通过动态刷新Token有效期,确保活跃用户不会因固定过期时间而被强制登出 提升用户体验:用户无需频繁重新登录,只要…...

港股IPO市场火爆 没有港卡如何参与港股打新?
据Wind资讯数据统计,今年1月1日至5月20日,港股共有23家企业IPO,较去年同期增加6家;IPO融资规模达600亿港元,较去年同期增长626.54%,IPO融资规模重回全球首位。 港股IPO市场持续火爆,不少朋友没有…...