Linux中的进程间通信之管道
管道
管道是Unix中最古老的进程间通信的形式。
我们把从一个进程连接到另一个进程的一个数据流称为一个“管道”
匿名管道
#include <unistd.h>
功能:创建一无名管道
原型
int pipe(int fd[2]);
参数
fd:文件描述符数组,其中fd[0]表示读端, fd[1]表示写端
返回值:成功返回0,失败返回错误代码
管道文件时一种内存级文件,没有名称,故为匿名管道
父进程打开文件然后fork创建子进程,子进程会继承父进程文件描述符表中的内容。
然后两个进程即可看到同一份文件。
一般而言管道只能用来进行单向的数据通信。
为什么让父进程以读和写的方式打开同一个文件?
为了让子进程看到读写端。
int fds[2];int n=pipe(fds);
代码实现
//1.创建管道文件打开读写端int fds[2];int n=pipe(fds);assert(n==0);//2.forkpid_t id=fork();assert(id>=0);if(id==0){//子进程写入close(fds[0]);const char* s="子进程,正在向父进程发消息";int cnt=0;while(true){cnt++;char buffer[1024];snprintf(buffer,sizeof buffer,"child->parent say: %s[%d][%d]",s,cnt,getpid());write(fds[1],buffer,sizeof(buffer));//系统接口不需要考虑'\0'sleep(1);}close(fds[1]);exit(0);}close(fds[1]);while(true){char buffer[1024];ssize_t s=read(fds[0],buffer,sizeof(buffer)-1);if(s>0)//s代表读到的字节数buffer[s]=0;cout<<"Get Message # "<<buffer<<"| mypid: "<<getpid()<<endl;}n=waitpid(id,nullptr,0);assert(n==id);close(fds[0]);
命名管道
命名管道可以从命令行上创建,命令行方法是使用下面这个命令:
mkfifo filename
命名管道也可以从程序里创建,相关函数有:
int mkfifo(const char *filename,mode_t mode);
创建命名管道:
int main(int argc, char *argv[])
{mkfifo("p2", 0644);return 0;
}
comm.hpp
#pragma once#include<iostream>
#include<cassert>
#include<cstdio>
#include<cstring>
#include<string>
#include<unistd.h>
#include<sys/wait.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<cerrno>
#include<fcntl.h>
using namespace std;
#define NAMED_PIPE "/tmp/mypipe.test"bool createFifo(const string& path)
{int n=mkfifo(path.c_str(),0666);if(n==0) return true;else{cout<<"errno: "<<errno<<" err string: "<<strerror(errno)<<endl;return false;}
}
void removeFifo(const string& path)
{int n=unlink(path.c_str());assert(n==0);
}
server.cc
#include"comm.hpp"using namespace std;int main()
{bool r=createFifo(NAMED_PIPE);assert(r);cout<<"server begin"<<endl;int rfd=open(NAMED_PIPE,O_RDONLY);cout<<"server end"<<endl;if(rfd<0) exit(1);//readchar buffer[1024];while (true){ssize_t s=read(rfd,buffer,sizeof(buffer)-1);if(s>0){buffer[s]=0;cout<<"client->server# "<<buffer;}else if(s==0){cout<<"client quit , me too"<<endl;break;}else{cout<<"err string--------"<<strerror(errno)<<endl;break;}}close(rfd);removeFifo(NAMED_PIPE);return 0;
}
clent.cc
#include"comm.hpp"using namespace std;int main()
{cout<<"client begin"<<endl;int wfd = open(NAMED_PIPE, O_WRONLY);cout<<"client end"<<endl;if (wfd < 0)exit(1);// writechar buffer[1024];while (true){cout << "Please Say# ";fgets(buffer, sizeof(buffer), stdin);if(strlen(buffer)>0) buffer[strlen(buffer)-1]=0;ssize_t n = write(wfd, buffer, strlen(buffer));assert(n == strlen(buffer));}close(wfd);return 0;
}
管道的读写特征
1. (读慢,写快)如果管道中没有了数据,读端在读,默认会直接阻塞当前正在读取的进程
2.(读快,写慢)管道是一个固定大小的缓冲区,写端写满时会阻塞,等待对方读取
3.(写端关闭,读到0)读端将数据读完后读到0结束进程。
4.读关闭,在写就没有意义了,OS会给写进程发送信号(13),将其终止。
管道的特征
1.管道的声明周期随进程
2.管道可以用来进行具有血缘关系的进程之间进行通信,常用于父子通信
3.管道是面向字节流的。按设置的最大字节数去读。
4.管道通信---半双工
sleep 1000 | sleep 2000
|:即为匿名管道
sleep的父进程为bash
综合案例
基于匿名管道的进程池设计
#include<iostream>
#include<vector>
#include<cassert>
#include<cstdio>
#include<cstring>
#include<ctime>
#include<string>
#include<unistd.h>
#include<sys/wait.h>
#include<sys/types.h>using namespace std;
#define PROCESS_NUM 5
#define MakeSeed() srand((unsigned long)time(nullptr))
typedef void(*func_t)();
void downLoadTask()
{cout<<getpid()<<" : downLoadTask()\n"<<endl;sleep(1);
}
void ioTask()
{cout<<getpid()<<" : ioTask()\n"<<endl;sleep(1);
}
void flushTask()
{cout<<getpid()<<" : flustTask()\n"<<endl;sleep(1);
}class subEp
{
public:subEp(pid_t subId,int writeFd):subId_(subId),writeFd_(writeFd){char nameBuffer[1024];snprintf(nameBuffer,sizeof nameBuffer,"process-%d[pid(%d)-fd(%d)]",num++,subId_,writeFd_);name_=nameBuffer;}
public:static int num;string name_;pid_t subId_;int writeFd_;
};
int subEp::num=0;void sendTask(const subEp& process,int taskNum)
{cout<<"send task num "<<taskNum<<" send to -> "<<process.name_<<endl;ssize_t n=write(process.writeFd_,&taskNum,sizeof(taskNum));assert(n==sizeof(int));
}
int recvTask(int readFd)
{int code=0;ssize_t s=read(readFd,&code,sizeof code);//assert(s==sizeof(int));if(s==4) return code;else if(s<=0) return -1;else return 0;
}
void createSubProcess(vector<subEp>* subs,vector<func_t>& funcMap)
{for(int i=0;i<PROCESS_NUM;++i){int fds[2];int n=pipe(fds);//父进程打开的文件是会被子进程共享的pid_t id=fork();if(id==0){//子进程close(fds[1]);while (true){//1.获取命令玛,如果没有,子进程应阻塞int commandCode = recvTask(fds[0]);//2.完成任务if(commandCode>0 && commandCode<funcMap.size()) funcMap[commandCode]();else if(commandCode==-1) break;;}exit(0);}close(fds[0]);subEp sub(id,fds[1]);subs->push_back(sub);}
}
void loadTaskFunc(vector<func_t>* out)
{assert(out);out->push_back(downLoadTask);out->push_back(ioTask);out->push_back(flushTask);
}
void loadBalanceContrl(const vector<subEp>& subs,const vector<func_t> &funcMap,int count)
{int processnum=subs.size();int tasknum=funcMap.size();//int cnt=subs.size();bool forever=(count==0)?true:false;while(true){//1.选择一个子进程--->vector<subEp> -> indexint subIdx=rand()%processnum;//2.选择一个任务---> vector<func_t>--->indexint taskIdx=rand()%tasknum;//3.任务发送给选择的进程sendTask(subs[subIdx],taskIdx);sleep(1);if(!forever){count--;if(count==0) break;}}//write quit -> read 0for(int i=0;i<processnum;++i) close(subs[i].writeFd_);
}
void waitProcess(vector<subEp> processes)
{int processnum=processes.size();for(int i=0;i<processnum;++i){waitpid(processes[i].subId_,nullptr,0);cout<<"wait sub process success ..."<<processes[i].subId_<<endl;}
}
int main()
{MakeSeed();//1.建立子进程并建立和子进程通信的信道vector<func_t> funcMap;loadTaskFunc(&funcMap);vector<subEp> subs;createSubProcess(&subs,funcMap);//2.父进程控制子进程int taskNum=3;loadBalanceContrl(subs,funcMap,taskNum);//3.回收子进程信息waitProcess(subs);return 0;
}
相关文章:

Linux中的进程间通信之管道
管道 管道是Unix中最古老的进程间通信的形式。 我们把从一个进程连接到另一个进程的一个数据流称为一个“管道” 匿名管道 #include <unistd.h> 功能:创建一无名管道 原型 int pipe(int fd[2]); 参数 fd:文件描述符数组,其中fd[0]表示读端, fd[1]表示写端 …...

【Vue】vue2项目打包后部署刷新404,配置publicPath ./ 不生效问题
Vue Router mode,为 history 无效,建议使用默认值 hash;...

【PyTorch】生成对抗网络
生成对抗网络是什么 概念 Generative Adversarial Nets,简称GAN GAN:生成对抗网络 —— 一种可以生成特定分布数据的模型 《Generative Adversarial Nets》 Ian J Goodfellow-2014 GAN网络结构 Recent Progress on Generative Adversarial Networks …...

Vue3轻松实现前端打印功能
文章目录 1.前言2.安装配置2.1 下载安装2.2 main.js 全局配置3.综合案例3.1 设置打印区域3.2 绑定打印事件3.3 完整代码4.避坑4.1 打印表格无边框4.2 单选框复选框打印不选中4.3 去除页脚页眉4.4 打印內容不自动换行1.前言 vue3 前端打印功能主要通过插件来实现。 市面上常用的…...
SHA-1 是一种不可逆的、固定长度的哈希函数,在 Git 等场景用于生成唯一的标识符来管理对象和数据完整性
SHA-1 (Secure Hash Algorithm 1) 是一种加密哈希函数,它能将任意大小的数据(如文件、消息)转换为一个固定长度的 160 位(20 字节)哈希值。这种哈希值通常以 40 个十六进制字符的形式表示,是数据的“指纹”…...

Activiti7 工作流引擎学习
目录 一. 什么是 Activiti 工作流引擎 二. Activiti 流程创建步骤 三. Activiti 数据库表含义 四. BPMN 建模语言 五. Activiti 使用步骤 六. 流程定义与流程实例 一. 什么是 Activiti 工作流引擎 Activiti 是一个开源的工作流引擎,用于业务流程管理…...
pytorch使用LSTM模型进行股票预测
文章目录 tushare获取股票数据数据预处理构建模型训练模型测试模型tushare获取股票数据 提取上证指数代码为603912的股票:佳力图,时间跨度为2014-01-01到今天十年的数据。 import tushare as ts pro = ts.pro_api()#准备训练集数据df = ts.pro_bar(ts_code=603912.SH, star…...
掌握 C# 异常处理机制
在任何编程语言中,处理错误和异常都是不可避免的。C# 提供了强大的异常处理机制,可以帮助开发者优雅地捕获和处理程序中的异常,确保程序的健壮性和可靠性。本文将带你了解 C# 中的异常类、try-catch 语句、自定义异常以及 finally 块的使用。…...
【Redis】Redis Cluster 简单介绍
Redis Cluster 是 Redis 3.0 提供的一种分布式解决方案, 允许数据在多个节点之间分散存储, 从而实现高可用性和可扩展性。 特点: 分片: Redis Cluster 将数据分散到多个节点, 通过哈希槽 (hash slots) 机制将键映射到不同的节点上。总共有 16384 个哈希槽, 每个节点负责一部分…...

【EXCEL数据处理】000010 案列 EXCEL文本型和常规型转换。使用的软件是微软的Excel操作的。处理数据的目的是让数据更直观的显示出来,方便查看。
前言:哈喽,大家好,今天给大家分享一篇文章!创作不易,如果能帮助到大家或者给大家一些灵感和启发,欢迎收藏关注哦 💕 目录 【EXCEL数据处理】000010 案列 EXCEL单元格格式。EXCEL文本型和常规型转…...

golang grpc进阶
protobuf 官方文档 基本数据类型 .proto TypeNotesGo Typedoublefloat64floatfloat32int32使用变长编码,对于负值的效率很低,如果你的域有可能有负值,请使用sint64替代int32uint32使用变长编码uint32uint64使用变长编码uint64sint32使用变长…...

Java JUC(三) AQS与同步工具详解
Java JUC(三) AQS与同步工具详解 一. ReentrantLock 概述 ReentrantLock 是 java.util.concurrent.locks 包下的一个同步工具类,它实现了 Lock 接口,提供了一种相比synchronized关键字更灵活的锁机制。ReentrantLock 是一种独占…...
使用rust写一个Web服务器——async-std版本
文章目录 实现异步代码并发地处理连接使用多线程提升性能 使用rust实现一个异步运行时是async-std的单线程Web服务器。 仓库地址: 1037827920/web-server: 使用rust编写的简单web服务器 (github.com) 在之前的单线程版本的Web服务器代码上进行修改,具体…...

C语言复习概要(一)
本文 C语言入门详解:从基础概念到分支与循环1. C语言常见概念1.1 程序的基本结构1.2 变量作用域和存储类1.3 输入输出1.4 编译与运行 2. C语言中的数据类型和变量2.1 基本数据类型2.2 变量的声明与初始化2.3 常量与枚举 3. C语言的分支结构3.1 if语句3.2 if-else语句…...

二、kafka生产与消费全流程
一、使用java代码生产、消费消息 1、生产者 package com.allwe.client.simple;import lombok.extern.slf4j.Slf4j; import org.apache.kafka.clients.producer.KafkaProducer; import org.apache.kafka.clients.producer.ProducerConfig; import org.apache.kafka.clients.pr…...

本地搭建OnlyOffice在线文档编辑器结合内网穿透实现远程协作
文章目录 前言1. 安装Docker2. 本地安装部署ONLYOFFICE3. 安装cpolar内网穿透4. 固定OnlyOffice公网地址 前言 本篇文章讲解如何使用Docker在本地Linux服务器上安装ONLYOFFICE,并结合cpolar内网穿透实现公网访问本地部署的文档编辑器与远程协作。 Community Editi…...

ScrapeGraphAI 大模型增强的网络爬虫
在数据驱动的动态领域,从在线资源中提取有价值的见解至关重要。从市场分析到学术研究,对特定数据的需求推动了对强大的网络抓取工具的需求。 NSDT工具推荐: Three.js AI纹理开发包 - YOLO合成数据生成器 - GLTF/GLB在线编辑 - 3D模型格式在线…...

PDF转换为TIF,JPG的一个简易工具(含下载链接)
目录 0.前言: 1.工具目录 2.工具功能(效果),如何运行 效果 PDF转换为JPG(带颜色) PDF转换为TIF(LZW形式压缩,可以显示子的深浅) PDF转换为TIF(CCITT形…...

Wireshark 解析QQ、微信的通信协议|TCP|UDP
写在前面 QQ,微信这样的聊天软件。我们一般称为im,Instant Messaging,即时通讯系统。那大家会不会有疑问,自己聊天内容会不会被黑客或者不法分子知道?这种体量的im是基于tcp还是udp呢?这篇文章我们就来探索…...
网络编程(5)——模拟伪闭包实现连接的安全回收
六、day6 今天学习如何利用C11模拟伪闭包实现连接的安全回收,之前的异步服务器为echo模式,但存在安全隐患,在极端情况下客户端关闭可能会导致触发写和读回调函数,二者都进入错误处理逻辑,进而造成二次析构。今天学习如…...
浏览器访问 AWS ECS 上部署的 Docker 容器(监听 80 端口)
✅ 一、ECS 服务配置 Dockerfile 确保监听 80 端口 EXPOSE 80 CMD ["nginx", "-g", "daemon off;"]或 EXPOSE 80 CMD ["python3", "-m", "http.server", "80"]任务定义(Task Definition&…...
ubuntu搭建nfs服务centos挂载访问
在Ubuntu上设置NFS服务器 在Ubuntu上,你可以使用apt包管理器来安装NFS服务器。打开终端并运行: sudo apt update sudo apt install nfs-kernel-server创建共享目录 创建一个目录用于共享,例如/shared: sudo mkdir /shared sud…...

(二)TensorRT-LLM | 模型导出(v0.20.0rc3)
0. 概述 上一节 对安装和使用有个基本介绍。根据这个 issue 的描述,后续 TensorRT-LLM 团队可能更专注于更新和维护 pytorch backend。但 tensorrt backend 作为先前一直开发的工作,其中包含了大量可以学习的地方。本文主要看看它导出模型的部分&#x…...

CMake基础:构建流程详解
目录 1.CMake构建过程的基本流程 2.CMake构建的具体步骤 2.1.创建构建目录 2.2.使用 CMake 生成构建文件 2.3.编译和构建 2.4.清理构建文件 2.5.重新配置和构建 3.跨平台构建示例 4.工具链与交叉编译 5.CMake构建后的项目结构解析 5.1.CMake构建后的目录结构 5.2.构…...
第25节 Node.js 断言测试
Node.js的assert模块主要用于编写程序的单元测试时使用,通过断言可以提早发现和排查出错误。 稳定性: 5 - 锁定 这个模块可用于应用的单元测试,通过 require(assert) 可以使用这个模块。 assert.fail(actual, expected, message, operator) 使用参数…...

第一篇:Agent2Agent (A2A) 协议——协作式人工智能的黎明
AI 领域的快速发展正在催生一个新时代,智能代理(agents)不再是孤立的个体,而是能够像一个数字团队一样协作。然而,当前 AI 生态系统的碎片化阻碍了这一愿景的实现,导致了“AI 巴别塔问题”——不同代理之间…...
AI编程--插件对比分析:CodeRider、GitHub Copilot及其他
AI编程插件对比分析:CodeRider、GitHub Copilot及其他 随着人工智能技术的快速发展,AI编程插件已成为提升开发者生产力的重要工具。CodeRider和GitHub Copilot作为市场上的领先者,分别以其独特的特性和生态系统吸引了大量开发者。本文将从功…...

dify打造数据可视化图表
一、概述 在日常工作和学习中,我们经常需要和数据打交道。无论是分析报告、项目展示,还是简单的数据洞察,一个清晰直观的图表,往往能胜过千言万语。 一款能让数据可视化变得超级简单的 MCP Server,由蚂蚁集团 AntV 团队…...

微软PowerBI考试 PL300-在 Power BI 中清理、转换和加载数据
微软PowerBI考试 PL300-在 Power BI 中清理、转换和加载数据 Power Query 具有大量专门帮助您清理和准备数据以供分析的功能。 您将了解如何简化复杂模型、更改数据类型、重命名对象和透视数据。 您还将了解如何分析列,以便知晓哪些列包含有价值的数据,…...

云原生安全实战:API网关Kong的鉴权与限流详解
🔥「炎码工坊」技术弹药已装填! 点击关注 → 解锁工业级干货【工具实测|项目避坑|源码燃烧指南】 一、基础概念 1. API网关(API Gateway) API网关是微服务架构中的核心组件,负责统一管理所有API的流量入口。它像一座…...