【Linux】匿名管道+进程池


文章目录

  • 前置知识
  • 一、管道的原理
  • 二、管道的特性
  • 三、管道的接口
  • 四、使用管道实现简单的进程池
    • 解决进程池的一个小问题


前置知识

一个进程在创建时,会默认打开三个文件,分别是:stdin,stdout,stderr
进程中有一个维护进程所打开的文件的文件描述对象结构体struct files_struct该文件描述对象结构体中包含一个fd_array,文件描述符表,这个文件描述符表存储的是对应打开的文件的文件描述对象的地址。也就是说,每一个文件都有对应的文件对象,来记录该文件的各种属性struct file。而进程对应的是文件描述对象,两者不同。
在这里插入图片描述
fd_array中存储的就是struct file*类型。

默认打开的三个文件中,stdin,stdout,stderr对应的分别是键盘文件,显示器文件,显示器文件,占用了fd_array文件描述符表中的0,1,2下标。

所以,进程再次创建文件时,会默认从3号下标开始记录。

一、管道的原理

在这里插入图片描述

父进程创建管道文件时,默认打开读端和写端,读端的文件fd存在3号下标中,写端文件存在4号下标中。
子进程被创建时会继承父进程的管理文件的对象,所以子进程的fd_array的3号和4号下标也记录了管道文件的读写端。

为了保证父子进程之间的通信,假设是父进程进行读取,子进程进行写入。
所以需要关闭父进程的写端,关闭子进程的读端。

在这里插入图片描述
子进程进行写入,父进程进行读取,就能实现通信了。

问题:为什么父进程不直接把要发送给子进程的数据保存一份,子进程在创建时就会继承这份数据了。

这种通信方式不是不可以,但只能静态通信。


实际上,在创建管道文件时,会创建两个文件对象,它们存储同一个inode,指向同一块缓冲区,这样就能实现子进程通过写端的struct file和父进程的读端的struct file进而看到同一个文件缓冲区,也就是让不同的进程看到同一份资源。

所以管道通信只能进行单向通信!!!

在这里插入图片描述

二、管道的特性

Linux中,管道的大小一般是4096字节(4KB)

管道的本质就是内存级文件。

  • 1.进程之间使用管道通信,必须具有血缘关系。常用于父子关系。
  • 2.管道通信只能进行单向通信。
  • 3.管道是基于文件的,而文件是随进程的,所以管道的生命周期随进程。
  • 4.这个管道文件,没有路径,没有名字,更没有inode,因为使用该管道文件,是由操作系统创建并管理的,而父子进程之间通过该管道进行通信的原因是继承,所以该管道就叫做匿名管道。
  • 5.父子进程是会进行进程协同,同步与互斥的。我的理解是:父子进程要向管道文件中读写内容,就要调用write和read系统调用,而该函数会进行阻塞地等待或读取。
    • 由此可知,管道的读写中有4种情况:
    • 1.读写端正常,如果管道为空,读端就要阻塞。
    • 2.读写端正常,如果管道被写满了,写端就要阻塞。
    • 3.读端正常读,写端关闭,读端就会读到0,表明读到了文件结尾,不会被阻塞。
    • 4.写端正常写,读端关闭,写端不会再写了,没有意义了,因为没人读。

操作系统所做的这一切,本质就是让不同的进程看到同一份资源。

三、管道的接口

在这里插入图片描述
该系统接口的参数是一个数组,数组有两个元素,记录的就是打开的管道文件的读端和写端在fd_array中的位置。

所以我们只需要传一个数组过去即可。

如果成功返回0,失败返回-1,且错误码被设置。

所以该参数叫做输出型参数

因为会把用户传进来的参数进行设置修改,所以用户可以再次使用该参数。

使用方法:

#define SIZE 2
int pipefd[SIZE] = {0};
int n = pipe(pipefd);

这是父进程申请管道文件,父进程需要读取,所以关闭写端

clode(pipefd[1]);

附带的一个函数:
在这里插入图片描述
printf函数我们熟悉,向显示器中打印格式化内容。
snprintf函数是printf函数的变形,本应该向显示器文件中打印的内容,变成向str指针指向的文件中打印size大小的格式化内容。

snprintf(buffer,sizeof(buffer),"%s-%d-%d",s.c_str(),self,cnt);

匿名管道的测试代码

#include <iostream>
#include <cstdio>
#include <string>
#include <cstring>
#include <cstdlib>
#include <cerrno>#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>#define SIZE 2
#define NUM 1024
using namespace std;// 1.先创建管道文件
// 2.创建子进程
// 3.子进程进行写入,父进程进行读取//向指定文件描述符对应文件写入
void Write(int wfd)
{string s = "Hello , i am child";char buffer[NUM];//getline(cin,buffer);pid_t self = getpid();int cnt = 5;while(cnt--){buffer[0] = 0; // 告诉读者我的buffer当作字符串来用snprintf(buffer,sizeof(buffer),"%s-%d-%d",s.c_str(),self,cnt);  cout << buffer << endl;write(wfd,buffer,strlen(buffer));sleep(1);}}void Read(int rfd)
{char buffer[NUM];while(true){buffer[0] = 0;ssize_t n = read(rfd,buffer,sizeof(buffer));//n是读取到的个数if(n > 0) {buffer[n] = '\0';cout << "father-" << getpid() <<  "get a message from child:[" << buffer << "]#" << endl;}else if(n == 0){cout << "father read file done!" << endl;break;}else break;sleep(1);}
}int main()
{int pipefd[SIZE] = {0};int n = pipe(pipefd);//成功返回0,失败返回-1if (n < 0) // 管道创建失败{perror("pipefd fail");return 1;}// 管道创建成功cout << "pipefd[0] : " << pipefd[0] <<  " pipefd[1] : " << pipefd[1] << endl; //创建子进程pid_t id = fork();if (id < 0){perror("fork fail");return 2;}// child : writeelse if (id == 0){//关闭读端close(pipefd[0]);//写入Write(pipefd[1]);//写入完成关闭写端close(pipefd[1]);exit(1);}// father : readclose(pipefd[1]);Read(pipefd[0]);int status = 0;pid_t rid = waitpid(id,&status,0); // 阻塞等待if(rid < 0)return 3;else if(rid > 0)cout << "wait child process success!" << endl;close(pipefd[0]);return 0;
}

四、使用管道实现简单的进程池

进程池:一个父进程通过创建多个子进程,然后将不同的任务派发给不同的进程,从而提高工作效率。

相比于接到一个任务后,再创建子进程,然后再将该任务交给子进程去做。

进程池的方法是一次创建多个子进程来待命,只要有任务,就可以立即派发,多个任务也能实现并行。

在这里插入图片描述

而父进程与子进程实现通信的方式就是管道通信

进程池代码

解决进程池的一个小问题

在父进程创建子进程时,子进程会继承父进程的struct files_struct,所以在创建第二个子进程时,由于它继承了父进程的信息,导致第二个子进程有能力去修改父进程与第一个子进程进行通信的管道文件。

所以在父进程不断创建子进程的过程中,子进程的fd_array空间被占用越来越多,意味着后面的子进程能修改前面的管道文件。

在这里插入图片描述

解决办法,在父进程创建第二个子进程开始,把该子进程中指向第一个管道文件的写端全部关闭。


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

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

相关文章

炫我出席数字光影工作室专业建设论坛,受聘为专家委员会委员!

11月18日&#xff0c;炫我科技受邀参加在北京深澜AI空间举办的2023数字光影工作室专业建设论坛。本次活动由北京市新媒体技师学院主办、北京澜景科技有限公司协办&#xff0c;私有云售前技术工程师龚琛代表我司出席&#xff0c;并受聘为新媒体技师学院数字光影工作室专家委员会…

Mysql基础操作(命令行)

文章目录 Mysql基础操作&#xff08;命令行&#xff09;背景创建数据库选择数据库查看所有表查看表结构向表插入数据插入第一条插入第二条插入第三条 查询表数据修改表数据删除表数据 Mysql基础操作&#xff08;命令行&#xff09; 背景 docker安装mysql8&#xff0c;映射本地…

GTC2023全球流量大会蓄势待发,菊风在7B57展位等你!

第六届 GTC 全球流量大会&#xff08;以下简称 GTC2023&#xff09;将于12月5日- 6日&#xff0c;在深圳福田会展中心7&#xff06;8号馆举办。 据悉&#xff0c;本届大会将是历届以来规模最大、参与人数最多、跨境出海资源最丰富的一次行业盛会。7、8 号馆共 15000 平方米&am…

计算机组成原理-磁盘存储器

文章目录 总览外存储器磁盘存储器磁盘的性能指标磁盘地址磁盘的工作过程磁盘阵列 总结 总览 外存储器 磁盘存储器 写是利用电流产生磁场从而写磁盘 读是利用载磁体移动时产生的电场从而得到数据 磁性材质易受外界磁场干扰 下图中 载磁体上N S的前后顺序代表对应存储二进制的比…

【深度学习】卷积神经网络(CNN)的参数优化方法

著名&#xff1a; 本文是从 Michael Nielsen的电子书Neural Network and Deep Learning的深度学习那一章的卷积神经网络的参数优化方法的一些总结和摘录&#xff0c;并不是我自己的结论和做实验所得到的结果。我想Michael的实验结果更有说服力一些。本书在github上有中文翻译的…

喜讯!云起无垠成为国家信息安全漏洞库(CNNVD)技术支撑单位

近日&#xff0c;云起无垠凭借其在漏洞挖掘、漏洞检测以及漏洞修复等领域的卓越表现&#xff0c;荣获“国家信息安全漏洞库&#xff08;CNNVD&#xff09;技术支撑单位等级证书&#xff08;三级&#xff09;”&#xff0c;正式成为CNNVD技术支撑单位。 中国国家信息安全漏洞库&…

MTK联发科MT6762/MT6763/MT6765安卓核心板参数规格比较

MT6762安卓核心板 MTK6762安卓核心板是一款工业级高性能、可运行 android9.0 操作系统的 4G智能模块。 CPU&#xff1a;4xCortex-A53 up to 2.0Ghz/4xCortex-A53 up to 1.5GhzGraphics&#xff1a;IMG GE8320 Up to 650MhzProcess&#xff1a;12nmMemory&#xff1a;1xLP3 9…

【正点原子STM32连载】 第六十章 串口IAP实验(Julia分形)实验 摘自【正点原子】APM32F407最小系统板使用指南

1&#xff09;实验平台&#xff1a;正点原子APM32F407最小系统板 2&#xff09;平台购买地址&#xff1a;https://detail.tmall.com/item.htm?id609294757420 3&#xff09;全套实验源码手册视频下载地址&#xff1a; http://www.openedv.com/thread-340252-1-1.html## 第六十…

实例分割12篇顶会论文及代码合集,含2023最新

同学们&#xff0c;你们觉得视觉经典四个任务中哪个最难&#xff1f;我个人觉得是实例分割。 因为它既具备语义分割的特点&#xff0c;需要做到像素层面上的分类&#xff0c;也具备目标检测的一部分特点&#xff0c;即需要定位出不同实例&#xff0c;即使它们是同一种类。 但…

LangChain的函数,工具和代理(一):OpenAI的函数调用

一、什么是函数调用功能 几个月前OpenAI官方发布了其API的函数调用功能(Function calling), 在 API 调用中&#xff0c;您可以描述函数&#xff0c;并让模型智能地选择输出包含调用一个或多个函数的参数的 JSON 对象。API函数“ChatCompletion” 虽然不会实际调用该函数&#…

一站式企业快递管理平台使用教程

因公寄件在企业中重要性的提升&#xff0c;催生出了企业快递管理平台。为什么这么说呢&#xff1f; 随着经济和快递行业的发展&#xff0c;因公寄件在企业中成了一件“常事”&#xff0c;寄文件合同、发票、节假日慰问品、样品等等&#xff0c;这种情况之下&#xff0c;因公寄件…

Vue3 设置点击后滚动条移动到固定的位置

需求&#xff1a; 点击不通过按钮&#xff0c;显示红框中表单&#xff0c;且滚动条滚动到底部 &#xff08;显示红框中表单默认不显示&#xff09; <el-button click"onApprovalPass">不通过</el-button> <div class"item" v-if"app…

pwn:[SWPUCTF 2021 新生赛]nc签到

题目 linux环境下显示为 配合题目的下载附件&#xff0c;发现过滤了一些&#xff0c;一旦输入这些会自动关闭程序 ls被过滤了&#xff0c;可以使用l\s cat和空格都被过滤了&#xff0c;cat可以换成c\at ,空格可以换成$IFS$9

Youtube0播放?运营教你需要的技巧、策略与工具!

对于有跨境意向的内容创作者或者品牌企业来说&#xff0c;YouTube是因其巨大的潜在受众群和商业价值成为最值得投入变现与营销计划的平台。 据统计&#xff0c;98% 的美国人每月访问 YouTube&#xff0c;近三分之二的人每天访问。但是&#xff0c;YouTube还远未达到过度饱和的…

酵母双杂交服务专题(一)

酵母双杂交系统是一种在酵母这种真核生物模型中执行的实验方法&#xff0c;用于探索活细胞内部蛋白质间的相互作用。这种技术能够敏感地捕捉蛋白质间的细微和短暂相互作用&#xff0c;通过检测报告基因的表达产物来实现。作为一种高度灵敏的技术&#xff0c;酵母双杂交系统被广…

Spring Cloud LoadBalancer 简单介绍与实战

前言 本文为SpringCloud的学习笔记&#xff0c;如有错误&#xff0c;希望各位高手能指出&#xff0c;主要介绍SpringCloudLoadBalancer的基本概念和实战 文章目录 前言什么是LoadBalancer负载均衡分类服务端负载均衡客户端负载均衡服务端负载均衡和客户端负载均衡的优缺点 常见…

评测|PolarDB MySQL 版 Serverless

评测&#xff5c;PolarDB MySQL 版 Serverless 目录 一、测试背景 1.1、云原生数据库 PolarDB Serverless新架构概念 1.2、Serverless资源弹性扩缩触发条件 二、PolarDB的Serverless能力与同类型产品进行对比 三、动态弹性升降资源的能力测试 3.1、测试资源 3.2、测试一…

ubuntu22.04在线安装redis,可选择版本

安装脚本7.0.5版本 在线安装脚本&#xff0c;默认版本号是7.0.5&#xff0c;可以根据需要选择需要的版本进行下载编译安装 sudo apt-get install gcc -y sudo apt-get install pkg-config -y sudo apt-get install build-essential -y#安装redis rm -rf ./tmp.log systemctl …

freeRTOS下载链接(sourceForge)

FreeRTOS Real Time Kernel (RTOS) download | SourceForge.net 文件名&#xff1a;FreeRTOSv202212.00.exe 双击后会自动变成这个样子的&#xff1a; 文件夹大小&#xff1a;506M 可以看到跟那个教程里面的文件结构是一模一样的&#xff0c;所以很可能是同一个最新版本的文件…