【lesson44】进程间通信之匿名管道

文章目录

  • 理解进程通信
  • 管道理解
  • 使用管道
    • 1.创建管道
    • 2.fork创建子进程
    • 3.构建单向通信信道
      • 子进程构建通信
      • 父进程构建通信
  • 使用管道的完整版代码
  • 扩展
    • Task.hpp
    • ProcessPool.cc

理解进程通信

进程运行具有独立性—>进程想通信,难度其实是比较大的---->进程通信的本质:先让不同的进程看到同一份资源(内存空间)----->而这个内存空间不能隶属与任何一个进程,更改强调共享

为什么要进程间通信:
为了达到交互数据、控制、通知等目标

进程通信不是目的,而是手段

进程间通信目的

  • 数据传输:一个进程需要将它的数据发送给另一个进程
  • 资源共享:多个进程之间共享同样的资源。
  • 通知事件:一个进程需要向另一个或一组进程发送消息,通知它(它们)发生了某种事件(如进程终止时要通知父进程)。
  • 进程控制:有些进程希望完全控制另一个进程的执行(如Debug进程),此时控制进程希望能够拦截另一个进程的所有陷入和异常,并能够及时知道它的状态改变。

进程间通信发展

  • 管道---->Linux原生提供的通信方式
  • System V进程间通信-----多进程------单机通信
  • POSIX进程间通信----->多线程----->网络通信

他们都有一定的标准,标准在使用者看来,更多是接口上具有一定规律性

管道理解

什么是管道?
感性理解:
管道有出口,有入口
天然气管道,石油管道,自来水管道…
只能单向通信
传输的都是资源
计算机管道也是传输的资源是数据!

什么是管道?
管道是Unix中最古老的进程间通信的形式。
我们把从一个进程连接到另一个进程的一个数据流称为一个“管道”
计算机通信领域的设计者,设计了一种单向通信的方式—管道
管道通信背后是进程之间通过管道进行通信。
在这里插入图片描述
1.分别一读写方式打开一个文件
在这里插入图片描述
2.fork创建子进程
在这里插入图片描述
3.双方各自关闭自己不需要的文件描述符
假设我们只要父进程写入,子进程读取
在这里插入图片描述
管道通信是纯内存形的通信方式,不要把数据写到磁盘

以前的指令

who | wc -l

其中|就是管道
在这里插入图片描述

使用管道

如何做到让不同的进程,看到同一份资源呢?-----fork让子进程继承的----能够让具有血缘关系的进程进行进程间通信—常用于父子进程

管道通信的步骤

1.创建管道

接口
在这里插入图片描述
其中参数pipefd是什么?
pipefd是输出型参数,我们调用pipe把管道的读写两端fd放进pipefd数组中。
在这里插入图片描述
开始创建pipe管道。
在这里插入图片描述
那么pipe的返回值,是什么呢?
在这里插入图片描述
因为错误会放回-1,所以我们直接进行断言,管道都没创建成功我们也没有必要通信。
在这里插入图片描述

2.fork创建子进程

在这里插入图片描述

3.构建单向通信信道

子进程读取,父进程写入
子进程保留读端关闭写端
父进程保留写端关闭读端
在这里插入图片描述

子进程构建通信

在这里插入图片描述

父进程构建通信

在这里插入图片描述

使用管道的完整版代码

#include <iostream>
#include <string>
#include <vector>
#include <cstdio>
#include <cstring>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <assert.h>int main()
{//1.创建管道int pipefd[2] = {0};//pipefd[0]是读端,pipefd[1]是写端int n = pipe(pipefd);assert(n != -1);(void)n;//因为后面不使用,所以直接转成(void)以免报错//2.创建子进程int id = fork();//3.构建单向通信信道,父进程写入子进程读取if(id == -1){//出错perror("create child failed:");}else if(id == 0){//子进程  读取//关闭写端close(pipefd[1]);ssize_t n = 0;//定义数据换出去char buffer[1024];//读取数据while(true){//读取数据n = read(pipefd[0],buffer,sizeof(buffer));//read返回值差错初六if(n > 0){//第n为置为'\0'因为系统不带'\0'buffer[n] = 0;//输出获取到的数据std::cout << "child get a message["<<getpid()<<"] Father# " << buffer << std::endl;}else if(n == 0){//Father写端进程退出不再写数据,child读端进程也退出不再读取数据std::cout << "Father quit,I quit too!" << std::endl;break;}}close(pipefd[0]);exit(0);}else{//父进程 写入//关闭读端close(pipefd[0]);//要发送的数据std::string message = "I am father,I am writting message from you";int count = 0;char buffer[1024];while(true){//构建一个能发生变化的字符串snprintf(buffer,sizeof(buffer),"%s[%d] : %d",message.c_str(),getpid(),count++);//发送数据write(pipefd[1],buffer,strlen(buffer));//故意发送数据慢点以便观察sleep(2);}close(pipefd[1]);//进程等待pid_t ret = waitpid(id,nullptr,0);std::cout << "id: " <<id << "ret: "<<ret << std::endl;assert(ret > 0);(void)ret;}return 0;
}

为什么前面我们不定义全局的buffer来进行通信呢?
因为有写时拷贝的存在,无法更改通信。

扩展

1.管道是用来进行具有血缘关系的进程之间进行通信(常用于父子进程),管道子进程读取数据会等父进程写入后再读,否则就不会读
显示器是一个文件,父子进程同时往显示器写入的时候,有没有说一个进程会等待另一个进程的情况?没有!----缺乏访问控制
管道文件—读取具有访问控制

2.管道具有通过让进程间协同的能力,因为提供了访问控制

3.管道提供面向流式服务----面向字节流

管道写的一方fd关闭,读取的一方read会返回0表示读到了文件结尾。

4.管道是基于文件的,文件的什么周期是随进程的,管道的什么周期也随进程。

管道特点

  • 只能用于具有共同祖先的进程(具有亲缘关系的进程)之间进行通信;通常,一个管道由一个进程创建,然后该进程调用fork,此后父、子进程之间就可应用该管道。
  • 管道提供流式服务
  • 一般而言,进程退出,管道释放,所以管道的生命周期随进程
  • 一般而言,内核会对管道操作进行同步与互斥
  • 管道是半双工的,数据只能向一个方向流动;需要双方通信时,需要建立起两个管道

管道是单向通信就是半双工通信的一种特殊情况,既可以读内容又可以写内容,但是写内容和读内容不能同时进行。

全双工:既可以读内容又可以写内容,读和写可以同时进行。

特殊情况:
1.读快写慢,管道没有数据的时候,读的一端必须等待写的一端。
2.写块读慢,管道写满了就不能再写了。
3.写端关闭,读端读取到0,表示读到文件结尾
4.读端关闭,写端继续写OS会自动终止进程

管道的作用?
父进程可以给子进程派发任务,也称进程池
在这里插入图片描述

Task.hpp

任务代码

#pragma once
#include <iostream>
#include <vector>
#include <string>
#include <unordered_map>
#include <functional>
#include <sys/types.h>
#include <unistd.h>typedef std::function<void()> func;std::vector<func> callbacks;
std::unordered_map<int,std::string> desc;void readMySQL()
{std::cout << "sub process["<<getpid()<<"] execute read MySQL task\n" << std::endl;
}void execuleUrl()
{std::cout << "sub process["<<getpid()<<"] execute execuleUrl task\n" << std::endl;
}void encryption()
{std::cout << "sub process["<<getpid()<<"] execute encryption task\n" << std::endl;
}void persistence()
{std::cout << "sub process["<<getpid()<<"] execute persistence task\n" << std::endl;
}void Load()
{desc.insert({callbacks.size(),"readMySQL"});callbacks.push_back(readMySQL);desc.insert({callbacks.size(),"execuleUrl"});callbacks.push_back(execuleUrl);desc.insert({callbacks.size(),"encryption"});callbacks.push_back(encryption);desc.insert({callbacks.size(),"persistence"});callbacks.push_back(persistence);
}void showHandler()
{for(const auto &iter : desc){std::cout << iter.first << "\t" << iter.second << std::endl;}
}int handlerSize()
{return callbacks.size();
}

ProcessPool.cc

#include <iostream>
#include <vector>
#include <unordered_map>
#include <cstdio>
#include <cstring>
#include <cassert>
#include <ctime>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <fcntl.h>
#include "Task.hpp"int waitcommand(int waitfd,bool &quit)//阻塞式等待
{uint32_t command = 0;//读取指令ssize_t n = read(waitfd,&command,sizeof(command));if(n == 0){quit = true;return -1;}assert(n == sizeof(uint32_t));return command;
}
void sendAndWakeup(pid_t who,int fd,uint32_t command)
{//发送指令write(fd,&command,sizeof(command));std::cout << "main process: call process " << who << " execute " << desc[command] << " through " << fd << std::endl;}#define PROCESS_NUM 5
int main()
{//加载任务Load();// 存储pid : pipefd的映射std::vector<std::pair<pid_t, int>> slots;// 创建子进程for (int i = 0; i < PROCESS_NUM; i++){// 创建管道int pipefd[2] = {0};int n = pipe(pipefd);assert(n == 0);//创建子进程int id = fork();if (id < 0){perror("create chlid failed");}else if (id == 0){// 子进程close(pipefd[1]);while (true){bool quit = false;//读取任务指令int command = waitcommand(pipefd[0], quit);if (quit)break;//执行任务if (command >= 0 && command < callbacks.size()){callbacks[command]();}else{std::cout << "the command unlawful" << std::endl;}}exit(1);}else{// 父进程,关闭读端close(pipefd[0]);//将每个进程的pid和pipefd存入pair<pid_t,int>数组中slots.push_back(std::pair<pid_t, int>(id, pipefd[1]));}}// 父进程派发任务srand((unsigned long)time(nullptr) ^ getpid() ^ 23323123123L); // 让数据源更随机while (true){int select = 0;int command = 0;printf("*****************************************\n");printf("**1.show handlers        2.send command**\n");printf("*****************************************\n");std::cout << "Please Enter Select:";std::cin >> select;if (select == 1){showHandler();}else if (select == 2){std::cout << "Please Enter command:";//选择任务std::cin >> command;//随机选择进程int choice = rand() % slots.size();//发送任务函数sendAndWakeup(slots[choice].first,slots[choice].second,command);}else{std::cout << "the select unlawful" << std::endl;}}//关闭所有子进程的fdfor(const auto& slot :  slots){close(slot.second);}//等待子进程退出,回收子进程所有信息for(const auto& slot :  slots){waitpid(slot.first,nullptr,0);}return 0;
}

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

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

PCA与梯度上升法

PAC 主成分分析&#xff08;Principal Component Analysis&#xff09; 一个非监督的机器学习算法主要用于数据的降维通过降维&#xff0c;可以发现更便于人类理解的特征其他应用&#xff1a;可视化&#xff1b;去噪 如何找到这个让样本间间距最大的轴&#xff1f; 如何定义样…

diffusers单机多卡推理(全网首发)

起因 博主在部署InstantID项目时&#xff0c;显存不够&#xff0c;想要将模型分散在多张卡上。 翻到这篇发现是分布式推理&#xff0c;博主一直以为这个可以达到我想要的效果&#xff0c;但是效果是多线程并行推理&#xff0c;并不能将一个模型切片在多个GPU上。 Distributed …

Stability AI一种新型随心所欲生成不同音调、口音、语气的文本到语音(TTS)音频模型

该模型无需提前录制人声样本作为参考&#xff0c;仅凭文字描述就能生成所需的声音特征。用户只需描述他们想要的声音特点&#xff0c;例如“一个语速较快、带有英国口音的女声”&#xff0c;模型即可相应地生成符合要求的语音。它不仅能模仿已有的声音&#xff0c;还能根据用户…

C语言--------指针(1)

0.指针&指针变量 32位平台&#xff0c;指针变量是4个字节&#xff08;32bit/84)--------x86 64位平台&#xff0c;指针变量是8个字节&#xff08;64bit/88)--------x64 编号指针地址&#xff1b;我们平常讲的p是指针就是说p是一个指针变量&#xff1b; ************只要…

构造 蓝桥OJ小蓝的无限集

样例输入 4 1 4 7 2 5 8 3 6 8 12 11 81 样例输出 No Yes No No #include<bits/stdc.h> using namespace std;using ll long long;bool rnk(ll a, ll b, ll n) {if((n-1) % b 0) return true;else if (a 1) return false;ll res 1;while(res < n){res * a;if (r…

【Linux驱动】块设备驱动(三)—— 块设备读写(不使用请求队列)

并非每种块设备都会用到请求队列&#xff0c;从上节可以知道&#xff0c;请求队列的作用是管理和调用IO请求&#xff0c;那么反过来想&#xff0c;如果IO请求较少&#xff0c;那就可以无需使用请求队列。在以下情况中&#xff0c;可以不使用请求队列。 单任务环境: 当系统中只有…

HarmonyOS class类对象基础使用

按我们之前的写法 就是 Entry Component struct Dom {p:Object {name: "小猫猫",age: 21,gf: {name: "小小猫猫",age: 18,}}build() {Row() {Column() {// ts-ignoreText(this.p.gf.name)}.width(100%)}.height(100%)} }直接用 Object 一层一层往里套 这…

机器学习——有监督学习和无监督学习

有监督学习 简单来说&#xff0c;就是人教会计算机学会做一件事。 给算法一个数据集&#xff0c;其中数据集中包含了正确答案&#xff0c;根据这个数据集&#xff0c;可以对额外的数据希望得到一个正确判断&#xff08;详见下面的例子&#xff09; 回归问题 例如现在有一个…

基于单片机的造纸纸浆液位控制系统结构设计

摘要:为适应无人化与高效化制浆造纸生产体系&#xff0c;造纸企业趋于以嵌入式技术优化造纸过 程中的纸浆液位控制系统&#xff0c;以单片机与传感器相互耦合实现纸浆液位控制。本文基于单片机 设计了造纸纸浆液位控制系统&#xff0c;其结构由控制模块、信息采集模块、物联网模…

图数据库 之 Neo4j - Browser 介绍(3)

Neo4j Browser 介绍 Neo4j Browser 中有 3 个模块&#xff0c;侧边栏&#xff0c;Cypher 编辑器与结果栏&#xff0c;在进入 Neo4j Browser 时结果栏会展示欢迎界面。 Cypher 编辑器 Cypher 是一种图形查询语言&#xff0c;用于查询和操作图形数据库。它是 Neo4j 图形数据库的…

uniapp+uView 【详解】录音,自制音频播放器

效果预览 代码实现 <template><view class"btnListBox"><view class"audioBox" v-if"audioLength"><u-row><u-col span"2"><u--text aligncenter :text"currentTime"></u--text>…

[Vulnhub靶机] DriftingBlues: 4

[Vulnhub靶机] DriftingBlues: 4靶机渗透思路及方法&#xff08;个人分享&#xff09; 靶机下载地址&#xff1a; https://download.vulnhub.com/driftingblues/driftingblues4_vh.ova 靶机地址&#xff1a;192.168.67.23 攻击机地址&#xff1a;192.168.67.3 一、信息收集 …

使用secure+xming通过x11访问ubuntu可视化程序

windows使用securexming通过x11访问ubuntu可视化程序 windows机器IP&#xff1a;192.168.9.133 ubuntu-desktop20.04机器IP&#xff1a;192.168.9.190 windows下载xming并安装 按照图修改xming配置 开始->xming->Xlaunch 完成xming会在右下角后台运行 windows在sec…

20240203在WIN10下使用GTX1080配置stable-diffusion-webui.git不支持float16精度出错的处理

20240203在WIN10下使用GTX1080配置stable-diffusion-webui.git不支持float16精度出错的处理 2024/2/3 21:23 缘起&#xff1a;最近学习stable-diffusion-webui.git&#xff0c;在Ubuntu20.04.6下配置SD成功。 不搞精简版本&#xff1a;Miniconda了。直接上Anacoda&#xff01; …

SpringBoot之事务源码解析

首先事务是基于aop的&#xff0c;如果不了解aop的&#xff0c;建议先去看下我关于aop的文章: Spring之aop源码解析  先说结论&#xff0c;带着结论看源码。首先&#xff0c;在bean的生命周期中&#xff0c; 执行实例化前置增强&#xff0c;会加载所有切面并放入缓存&#xff0…

汉字拼音桥接交流与传承的关键

汉字拼音&#xff0c;一种基于拉丁字母为汉字标注读音的发音指导系统&#xff0c;自20世纪50年代推广以来便成为学习汉语的基石。这种独特的拼写系统不仅在汉语的教育与学习领域起到不可替代的作用&#xff0c;而且对文化的传承、科技的进步以及国际交流都产生了深远的影响。 汉…

MFC实现遍历系统进程

今天我们来枚举系统中的进程和结束系统中进程。 认识几个API 1&#xff09;CreateToolhelp32Snapshot 用于创建系统快照 HANDLE WINAPI CreateToolhelp32Snapshot( __in DWORD dwFlags, //指定快照中包含的系统内容__in DWORD th32P…

如何使用CLZero对HTTP1.1的请求走私攻击向量进行模糊测试

关于CLZero CLZero是一款功能强大的模糊测试工具&#xff0c;该工具可以帮助广大研究人员针对HTTP/1.1 CL.0的请求走私攻击向量进行模糊测试。 工具结构 clzero.py - 工具主脚本&#xff1b; default.py - 包含了大多数标准攻击测试方法和字符&#xff1b; exhaustive.py - 包…

微信公众号接入智能聊天机器人

微信公众号免费接入智能聊天机器人 准备物料操作步骤1.准备1个域名2.讯飞星火认知大模型3.github帐号4.vercel1.登录[vercel](https://vercel.com/login),使用github帐号登录2.创建一个新应用&#xff0c;通过github导入(它会自动拉取github仓库的项目)3.添加domains 5.微信公众…

【MySQL】学习和总结DCL的权限控制

&#x1f308;个人主页: Aileen_0v0 &#x1f525;热门专栏: 华为鸿蒙系统学习|计算机网络|数据结构与算法 ​&#x1f4ab;个人格言:“没有罗马,那就自己创造罗马~” #mermaid-svg-Bl9kYeLf8GfpdQgL {font-family:"trebuchet ms",verdana,arial,sans-serif;font-siz…