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;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/437598.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

解锁PDF阅读器的神奇功能与应用场景

PDF格式的文档因其稳定性、兼容性和安全性&#xff0c;成为了广泛传播和存储信息的重要载体。而PDF阅读器则是我们打开这个数字知识宝库的关键钥匙。接下来&#xff0c;让我们一同走进福昕PDF阅读器和它小伙伴们的世界&#xff0c;去探索它们的神奇之处。 1.福昕阅读器 链接一…

Spring Boot 和 MyBatis-Plus凑一块儿了,这份教程你得看

一、引言 MyBatis-Plus 是 MyBatis 的增强版&#xff0c;提供了 CRUD 接口、分页插件、性能分析插件等特性&#xff0c;简化了开发过程。本文将详细介绍如何在 Spring Boot 项目中集成 MyBatis-Plus。 支持的数据看也越来越多&#xff0c;值得去搞一下&#xff0c;写了一个小例…

Hive数仓操作(八)

一、Hive中的分桶表 1. 分桶表的概念 分桶表是Hive中一种用于提升查询效率的表类型。分桶指的是根据指定列的哈希值将数据划分到不同的文件&#xff08;桶&#xff09;中。 2. 分桶表的原理 哈希分桶&#xff1a;根据分桶列计算哈希值&#xff0c;对哈希值取模&#xff0c;将…

三维激光扫描技术在文保修缮项目中的应用

三维激光扫描技术作为一种新兴的高精度空间数据获取手段&#xff0c;其在文物保护和修缮项目中的应用日益广泛。这项技术通过快速获取物体表面的三维密集点云数据&#xff0c;为文物的数字化存档、保护、修复及再利用提供了强有力的技术支持。 数据采集&#xff1a;高精度与非接…

Python案例--水仙花数的探索之旅

一、引言 水仙花数&#xff0c;也称为阿姆斯特朗数&#xff0c;是一种特殊的三位数&#xff0c;其各位数字的立方和等于其本身。例如&#xff0c;153就是一个水仙花数&#xff0c;因为 135333153135333153。这种数字的发现不仅展示了数字的内在美&#xff0c;也激发了人们对数…

Element-plus安装及其基础组件使用

简而言之&#xff0c;在main.js中导出以下库,仅此&#xff0c;搞多了出错难排查 import ElementPlus from element-plus //导入ElementPlus 模块 import element-plus/dist/index.css //引入样式 app.use(ElementPlus) //注册库就能使用了 Element Plus 是一个基于 Vue 3 的组件…

《Linux从小白到高手》理论篇(十一):Linux的系统环境管理

值此国庆佳节&#xff0c;深宅家中&#xff0c;闲来无事&#xff0c;就多写几篇博文。本篇详细深入介绍Linux的系统环境管理。 环境变量 linux系统下&#xff0c;如果你下载并安装了应用程序&#xff0c;很有可能在键入它的名称时出现“command not found”的提示内容。如果每…

2024必备英语在线翻译工具推荐

英语在线翻译工具就如同一位随时待命的语言助手&#xff0c;为我们打破语言障碍&#xff0c;搭建起沟通的桥梁。接下来&#xff0c;让我们一起深入了解这些英语在线翻译工具的丰富功能及其为我们带来的便利。 1.福昕在线翻译 链接直达>>https://fanyi.pdf365.cn/doc …

命令按钮QLink

主要作用用来点击后可以自动打开系统的网页浏览器&#xff0c;跳转到指定的网页 常用方法 文本 //获取和设置文本 QString text() const void setText(const QString &text)描述信息 //获取和设置描述文本 QString description() const void setDescription(const QSt…

【RabbitMQ】面试题

在本篇文章中&#xff0c;主要是介绍RabbitMQ一些常见的面试题。对于前几篇文章的代码&#xff0c;都已经在码云中给出&#xff0c;链接是mq-test: 学习RabbitMQ的一些简单案例 (gitee.com)&#xff0c;如果存在问题的话欢迎各位提出&#xff0c;望共同进步。 MQ的作用以及应用…

【web安全】——XXE漏洞

1.XML基础 1.1.XML简介 XML被称为可扩展标记语言&#xff0c;与HTML类似&#xff0c;但是HTML中的标签都是预定义(预先定义好每个标签的作用)的&#xff0c;而XML语言中的标签都是自定义(可以自己定义标签的名称、属性、值、作用)的;HTML中的标签可以是单标签&#xff0c;而X…

SpringMVC源码-SpringMVC框架中Spring父容器和SpringMVC子容器加载的流程以及SpringMVC九大内置组件的初始

一、Spring父容器启动 SpringMVC 的项目结构如下: applicationContext.xml spring的配置文件 <?xml version"1.0" encoding"UTF-8"?> <beans xmlns"http://www.springframework.org/schema/beans"xmlns:xsi"http://www.w3.o…

机器学习西瓜书笔记(十三) 第十三章半监督学习+代码

第十三章 13 半监督学习13.1 未标记样本13.3.1 小结 13.2 生成式方法13.2.1 小结 13.3 半监督SVM13.3.1 小结 13.4 图半监督学习13.4.1 小结 13.5 基于分歧的方法13.5.1 小结 13.6 半监督聚类13.6.1 小结 13.7 代码&#xff1a;手写数据集上的标签传播-性能展示章末小结 13 半监…

数据结构——初识树和二叉树

线性结构是一对一的关系&#xff0c;意思就是只有唯一的前驱和唯一的后继&#xff1b; 非线性结构&#xff0c;如树形结构&#xff0c;它可以有多个后继&#xff0c;但只有一个前驱&#xff1b;图形结构&#xff0c;它可以有多个前驱&#xff0c;也可以有多个后继。 树的定义…

变电站红外检测数据集 1180张 变电站红外 标注voc yolo 13类

变电站红外检测数据集 1180张 变电站红外 标注voc yolo 13类 变电站红外检测数据集 名称 变电站红外检测数据集 (Substation Infrared Detection Dataset) 规模 图像数量&#xff1a;1185张图像。类别&#xff1a;13种设备类型。标注个数&#xff1a;2813个标注。 数据划分…

多模态RAG实现

在标准 RAG 中&#xff0c;输入文档包含文本数据。LLM 利用上下文学习&#xff0c;通过检索与所提查询上下文相匹配的文本文档块来提供更相关、更准确的答案。 但是&#xff0c;如果文档包含图像、表格、图表等以及文本数据&#xff0c;该怎么办&#xff1f; 不同的文档格式包…

华为GaussDB数据库之Yukon安装与使用

一、Yukon简介 Yukon&#xff08;禹贡&#xff09;&#xff0c;基于openGauss、PostgreSQL、GaussDB数据库扩展地理空间数据的存储和管理能力&#xff0c;提供专业的GIS&#xff08;Geographic Information System&#xff09;功能&#xff0c;赋能传统关系型数据库。 Yukon 支…

linux桌面软件(wps)内嵌到其他窗口

程序测试环境是&#xff1a;slackware系统&#xff0c;属于linux系统&#xff0c;有桌面&#xff08;Xface Session&#xff09;。系统镜像是&#xff1a;slackware64-15.0-install-dvd.iso。qt、c代码实现。 程序功能&#xff1a;将已经打开的wps&#xff08;word、pdf等都可…

Android SystemUI组件(09)唤醒亮屏 锁屏处理流程

该系列文章总纲链接&#xff1a;专题分纲目录 Android SystemUI组件 本章关键点总结 & 说明&#xff1a; 说明&#xff1a;本章节持续迭代之前章节的思维导图&#xff0c;主要关注左侧上方锁屏分析部分 唤醒亮屏 即可。 Power按键的处理逻辑最终是由PhoneWindowManager来…

Watchdog Timers(WDT)

文章目录 1. 介绍2. Feature List3. 概述3.1. Safety Watchdog3.2. CPU Watchdog 4. 看门狗定时器功能5. Endinit Functions5.1 Password Access to WDTxCON05.1.1 Static Password5.1.2 Automatic Password Sequencing 5.2 Check Access to WDTxCON05.3 Modify Access to WDTx…