当前位置: 首页 > news >正文

【Linux学习】进程间通信之 匿名管道 与 基于管道的进程池

🍑个人主页:Jupiter.
🚀 所属专栏:Linux从入门到进阶
欢迎大家点赞收藏评论😊

在这里插入图片描述

在这里插入图片描述

目录

  • `🍑进程间通信`
    • `🐬进程间通信目的 `
  • `📚管道 `
    • `📕管道的原理`
      • `🐧用fork来共享管道原理`
      • `🦌站在文件描述符角度-深度理解管道`
    • `🚀匿名管道 `
      • `🔒管道读写规则`
      • ` 🐟管道特点`
    • `🦅基于管道实现一个进程池`


🍑进程间通信

🐬进程间通信目的

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

进程间通信的实质让不同的进程看到一份资源

📚管道

什么是管道?

管道是Unix中最古老的进程间通信的形式。
我们把从一个进程连接到另一个进程的一个数据流称为一个“管道”,其中,管道只能被设计为单向通信的。

在这里插入图片描述

📕管道的原理

🐧用fork来共享管道原理

在这里插入图片描述

🦌站在文件描述符角度-深度理解管道

  • 当一个进程以读和以写打开同一个文件的时候,会有两个struct file对象(如下图),一个被打开的文件只有一个文件缓冲区,所以这两个struct file对象指向的是同一个缓冲区。(struct file允许多个指针指向的,里面有引用计数,当上层调用close的时候,实际上是将对应的struct file* fd_struct里面的数据清空,然后引用计数–,为0就会回收对应的文件缓冲区)
  • 当我们fork创建子进程后,会以父进程为模板,将进程独有的资源拷贝给子进程(浅拷贝)。
  • 这时,子进程也指向父进程所指向的那两个struct file对象,两个进程就看到了同一份资源(缓冲区)。
  • 将父子进程对应的读或则写端关闭,就形成了单向的管道。

在这里插入图片描述

🚀匿名管道

OS提供的一个系统调用pipe,调用后OS还是使用文件那一套,只需创建一个内存级文件对象与文件缓冲区,但并不是真的打开了一个文件,其中磁盘中并不存在这个文件,不需要向磁盘做刷新;
头文件: #include <unistd.h>
功能:创建一无名管道
原型:

  • int pipe(int fd[2]);
  • 参数:
    • fd:文件描述符数组,其中fd[0]表示读端, fd[1]表示写端
    • 返回值:成功返回0,失败返回错误代码。

在这里插入图片描述

示例代码:

void writer(int wfd)
{const char *str = "hello father, I am child";char buffer[128];snprintf(buffer, sizeof(buffer), "%s", str);write(wfd, buffer, strlen(buffer)); 
}
void reader(int rfd)
{char buffer[1024];ssize_t n = read(rfd, buffer, sizeof(buffer)-1);(void)n;printf("father get a message: %s", buffer);
}int main()
{// 1. 创建管道int pipefd[2];int n = pipe(pipefd);if(n < 0) return 1;printf("pipefd[0]: %d, pipefd[1]: %d\n", pipefd[0], pipefd[1]); // 3, 4// 2. 创建子进程  pid_t id = fork();if(id == 0){//子进程作为写端,关闭读close(pipefd[0]);writer(pipefd[1]);exit(0);}//父进程作为读端,关闭写close(pipefd[1]);reader(pipefd[0]);wait(NULL);return 0;
}

🔒管道读写规则

  • 管道内部没有数据并且写端没有关闭自己的fd,读端就会阻塞等待,直到pipe中有数据。
  • 管道内部写满数据并且读端没有关闭自己的fd,写端就会阻塞等待,直到pipe中有空间可以写。
  • 如果所有管道写端对应的文件描述符被关闭,则read返回0,表示读结束,类似读到了文件结尾。
  • 如果所有管道读端对应的文件描述符被关闭,则write操作会产生信号SIGPIPE,进而可能导致write进程退出

🐟管道特点

  • 只能用于具有共同祖先的进程(具有亲缘关系的进程)之间进行通信;通常,一个管道由一个进程创建,然后该进程调用fork,此后父、子进程之间就可应用该管道。
  • 管道是面向字节流的。
  • 一般而言,进程退出,管道释放,所以管道的生命周期随进程。
  • 一般而言,内核会对管道操作进行同步与互斥。
  • 当要写入的数据量不大于PIPE_BUF时,linux将保证写入的原子性。当要写入的数据量大于PIPE_BUF时,linux将不再保证写入的原子性。(PIPE_BUF==4096字节
  • 管道是半双工的,数据只能向一个方向流动(单向通信 );需要双方通信时,需要建立起两个管道 。
    在这里插入图片描述

🦅基于管道实现一个进程池

实现目标:创建多个子进程,父进程通过管道向子进程发送任务,对子进程进行控制,使子进程能够负载均衡的完成父进程提供的任务。

#pragma once#include<iostream>
#include<cstdlib>
#include<unistd.h>using namespace std;typedef void(*work_t)();
typedef void(*task_t)();void Printlog()
{cout<<"Printlog"<<endl;
}
void callone()
{cout<<"callone"<<endl;
}
void ConnectMysql()
{cout<<"ConnectMysql"<<endl;
}task_t tasks[3]={ Printlog , callone , ConnectMysql};uint32_t nextwork()
{return rand()%3;
}void worker()
{while(true){uint32_t command_code = 0;ssize_t n = read(0,&command_code,sizeof(command_code));if(n==sizeof(command_code)){if(command_code>=3) continue;tasks[command_code]();}else if(n==0){break;}}}
#include <iostream>
#include <unistd.h>
#include <string>
#include <cstdlib>
#include<sys/wait.h>
#include <vector>
#include <ctime>
#include "task.hpp"using namespace std;#define Subprocnum 5enum
{UsageError = 1,NumError,PipeError
};void Usage(const string &proc)
{cout << "Usage:" << proc << "-Subprocnum" << endl;
}
//./myprocess 6class channel
{
public:channel(int wfd, pid_t Sub_id, const string &name): _wfd(wfd),_id(Sub_id),_name(name){}int wfd(){return _wfd;}void Close(){close(_wfd);}pid_t id(){return _id;}~channel(){}private:int _wfd;pid_t _id;string _name;
};class processpool
{
public:processpool(int sub_num): _Sub_num(sub_num){}int Nextchannel(){static int next = 0;int n = next++;next %= channels.size();return n;}int Creatproc(work_t worker){vector<int> fds;for (int num = 0; num < _Sub_num; num++){int pipefd[2] = {0};int n = pipe(pipefd);if (n < 0)return PipeError;pid_t id = fork();if (id == 0){if(!fds.empty()){for(auto fd:fds){close(fd);}}// child   rclose(pipefd[1]);dup2(pipefd[0], 0);worker();exit(0);}string cname = "channel-" + to_string(num);// father   wclose(pipefd[0]);channels.push_back(channel(pipefd[1], id, cname));fds.push_back(pipefd[1]);}return 0;}void Send_task(int nextchannel, uint32_t code){int wfd = channels[nextchannel].wfd();write(wfd, &code, sizeof(code));}void Killall(){for(auto &channel:channels){channel.Close();}}void wait(){for(auto &channel:channels){int status = 0;pid_t rid = waitpid(channel.id(),&status,0);if(rid==channel.id()){cout<<"wait success..."<<endl;}}}~processpool(){}private:int _Sub_num;vector<channel> channels;
};int Col(processpool *processpool_ptr)
{while (true){// a.选择进程与通道int nextchannel = processpool_ptr->Nextchannel();// b.选择任务uint16_t code = nextwork();// c.发送任务processpool_ptr->Send_task(nextchannel, code);}return 0;
}
int main(int argc, char *argv[])
{if (argc != 2){Usage(argv[0]);return UsageError;}int Subnum = stoi(argv[1]);if (Subnum < 0)return NumError;srand((uint32_t)time(NULL));// 1. 创建进程processpool *processpool_ptr = new processpool(Subnum);processpool_ptr->Creatproc(worker);// 2.控制进程Col(processpool_ptr);// 3.回收进程//  wait process//杀掉所有的进程processpool_ptr->Killall();//等待所有进程processpool_ptr->wait();delete(processpool_ptr);return 0;
}

代码中细节处理:在创建子进程代码中已经处理。
在这里插入图片描述


相关文章:

【Linux学习】进程间通信之 匿名管道 与 基于管道的进程池

&#x1f351;个人主页&#xff1a;Jupiter. &#x1f680; 所属专栏&#xff1a;Linux从入门到进阶 欢迎大家点赞收藏评论&#x1f60a; 目录 &#x1f351;进程间通信&#x1f42c;进程间通信目的 &#x1f4da;管道 &#x1f4d5;管道的原理&#x1f427;用fork来共享管道原…...

小团队如何选需求管理软件?8款顶级推荐

本文将分享8款适合小团队的需求管理软件&#xff1a;PingCode、Worktile、Tapd、Teambition、禅道、Asana、Jama Connect、Aha!。 在小团队中管理需求时&#xff0c;寻找合适的软件工具常常让人头疼&#xff0c;不同的需求管理软件提供各种功能&#xff0c;但哪些功能真正适合…...

docker操作入门

1.创建镜像&#xff0c;使用当前文件 docker build -t experience . 2.运行容器 docker run -d -p 8501:8501 --name my-running-app my-python-api docker run -p 8508:8508 experience docker run -p 8508:8508 -p 8509:8509 experience 3.查看容器状态 docker ps docker p…...

简单的射箭小游戏网页源码

简单的射箭小游戏网页源码,对准靶心开启你的射击之旅吧 微信扫码免费获取源码...

Python | Leetcode Python题解之第331题验证二叉树的前序序列化

题目&#xff1a; 题解&#xff1a; class Solution:def isValidSerialization(self, preorder: str) -> bool:pre 1for i in preorder.split(,):if i.isdigit():if pre 0:return Falsepre 1else:if pre 0:return Falsepre - 1return pre 0...

0x3 “护网行动”守之道

一、护网防守目标系统 二、护网防守之利器 通过安全流程控制、安全技术保障、安全工具支撑、安全能力提升四个层次全面构成安全防御体系。 安全技术名称解释 IPS&#xff08;入侵防御系统&#xff09;WAF&#xff08;Web应用防火墙&#xff09;IDS&#xff08;入侵检测系统&a…...

白骑士的Matlab教学高级篇 3.1 高级编程技术

系列目录 上一篇&#xff1a;白骑士的Matlab教学进阶篇 2.5 Simulink 高级编程技术在MATLAB中扮演着至关重要的角色&#xff0c;帮助用户更高效地编写复杂程序、提高代码的可维护性和可读性。本节将介绍面向对象编程、函数句柄与回调函数、错误处理与调试的相关内容。 面向对…...

haproxy简介与用法

一、负载均衡 1.1、概念&#xff1a; 负载均衡SLB&#xff08;Server Load Balancer&#xff09;是一种对流量进行按需分发的服务&#xff0c;通过将流量分发到不同的后端服务来扩展应用系统的服务吞吐能力&#xff0c;并且可以消除系统中的单点故障&#xff0c;提升应用系统…...

Geoscene Pro的三维

一、场景设置 1.3D视图分为全局场景和局部场景。在Geoscene Pro中&#xff0c;两个场景可以自由切换。 &#xff08;1&#xff09;全局场景有固定的坐标系GCS&#xff08;WGS84、CGCS2000&#xff09;&#xff0c;并在全球比例尺下展示&#xff08;全球范围&#xff09;。可以…...

论文阅读 - Scaling Up k-Clique Densest Subgraph Detection | SIGMOD 2023

1. 论文背景 密集子图发现&#xff08;Densest Subgraph Discovery&#xff09;是图挖掘领域的一个基础研究方向&#xff0c;并且近年来在多个应用领域得到了广泛研究。特别是在生物学、金融学和社交网络分析等领域&#xff0c;密集子图的发现对理解复杂网络结构和行为具有重要…...

前端框架(三件套)

学习网站 HTML 系列教程&#xff08;有广告&#xff09; HTML&#xff08;超文本标记语言&#xff09; | MDN (mozilla.org)&#xff08;英文不太友好&#xff09; 1.HTML5 & CSS3 1.1HTML5表格 <!DOCTYPE html> <html lang"en"> <head>…...

MemoryCache 缓存 实用

MemoryCache 缓存 实用,相关逻辑代码里已详细注释&#xff0c; 在Java中创建一个单例模式&#xff08;Singleton Pattern&#xff09;的MyMemoryCache类&#xff0c;可以采用多种方法&#xff0c;其中最常见的是使用“饿汉式”和“懒汉式”&#xff08;线程安全和非线程安全&am…...

Java设计模式(命令模式)

定义 将一个请求封装为一个对象&#xff0c;从而让你可以用不同的请求对客户进行参数化&#xff0c;对请求排队或者记录请求日志&#xff0c;以及支持可撤销的操作。 角色 抽象命令类&#xff08;Command&#xff09;&#xff1a;声明用于执行请求的execute方法&#xff0c;通…...

什么是 CI/CD?

什么是 CI/CD&#xff1f; CI/CD&#xff08;Continuous Integration/Continuous Deployment&#xff09;是一种软件开发实践&#xff0c;旨在通过自动化的方式频繁地构建、测试和发布软件。CI/CD 可以显著提高软件交付的速度和质量&#xff0c;使团队能够更快地响应市场变化和…...

【免费】最新区块链钱包和私钥的助记词碰撞器,bybit使用python开发

使用要求 1、用的是google里面的扩展打包成crx文件&#xff0c;所以在使用之前你需要确保自己电脑上有google浏览器&#xff0c;而且google浏览器版本需要在124之上。&#xff08;要注意一下&#xff0c;就是电脑只能有一个Chrome浏览器&#xff09; 2、在win10上用vscode开发…...

【苍穹外卖JAVA项目】第2天:新增员工

在EmployeeMapper.java中插入数据&#xff1a;一、新增员工 1.产品原型 2.接口设计 由于需要提交员工信息&#xff0c;用post请求方式&#xff0c;可以携带json数据 3.设计数据库的employee表 4.设计DTO 数据传输对象&#xff08;DTO&#xff09;&#xff1a;封装前端提交过…...

队列的实现及循环队列

一、队列的概念及结构 队列只允许在一端进行插入数据操作&#xff0c;在另一端进行删除数据操作的特殊线性表。队列具有先进先出FIFO&#xff08;Fist In First Out&#xff09;。 入队列&#xff1a;进行插入操作的一端称为队尾。 出队列&#xff1a;进行删除操作的一端称为…...

docker部署zookeeper和kafka

docker部署zookeeper和kafka zookeeperkafkakafka-eagle zookeeper firewall-cmd --zonepublic --add-port2181/tcp --permanent firewall-cmd --reload docker pull zookeeper:3.4.14 docker run -d --name zk -p 2181:2181 zookeeper:3.4.14mkdir -p /root/zookeeper/data m…...

(13)zabbix的监控-1

前言&#xff1a;在上一次的基础上&#xff0c;完成实验。 1、添加一个空模板&#xff0c;方便 2、添加空模板到主机192.168.121.50 client-one里面模板是空的 4、在主机添加监控项和图形 5、自定义监控项&#xff0c;在客户端定义 [rootclient1 ~]# vim /etc/zabbix/zabbix_…...

Redis相关面试题(二)

一、Bit中不同命令使用的场景 二、什么是缓存击穿&#xff0c;缓存穿透&#xff0c;缓存雪崩&#xff1f; 缓存击穿&#xff1a;是指当某一个key的缓存过期时大并发量的请求同时访问key&#xff0c;瞬间击穿服务器直接访问到数据库&#xff0c;使得数据库处于负载情况 缓存穿透…...

反射获取方法和属性

Java反射获取方法 在Java中&#xff0c;反射&#xff08;Reflection&#xff09;是一种强大的机制&#xff0c;允许程序在运行时访问和操作类的内部属性和方法。通过反射&#xff0c;可以动态地创建对象、调用方法、改变属性值&#xff0c;这在很多Java框架中如Spring和Hiberna…...

C# 类和继承(抽象类)

抽象类 抽象类是指设计为被继承的类。抽象类只能被用作其他类的基类。 不能创建抽象类的实例。抽象类使用abstract修饰符声明。 抽象类可以包含抽象成员或普通的非抽象成员。抽象类的成员可以是抽象成员和普通带 实现的成员的任意组合。抽象类自己可以派生自另一个抽象类。例…...

数据库分批入库

今天在工作中&#xff0c;遇到一个问题&#xff0c;就是分批查询的时候&#xff0c;由于批次过大导致出现了一些问题&#xff0c;一下是问题描述和解决方案&#xff1a; 示例&#xff1a; // 假设已有数据列表 dataList 和 PreparedStatement pstmt int batchSize 1000; // …...

成都鼎讯硬核科技!雷达目标与干扰模拟器,以卓越性能制胜电磁频谱战

在现代战争中&#xff0c;电磁频谱已成为继陆、海、空、天之后的 “第五维战场”&#xff0c;雷达作为电磁频谱领域的关键装备&#xff0c;其干扰与抗干扰能力的较量&#xff0c;直接影响着战争的胜负走向。由成都鼎讯科技匠心打造的雷达目标与干扰模拟器&#xff0c;凭借数字射…...

零基础在实践中学习网络安全-皮卡丘靶场(第九期-Unsafe Fileupload模块)(yakit方式)

本期内容并不是很难&#xff0c;相信大家会学的很愉快&#xff0c;当然对于有后端基础的朋友来说&#xff0c;本期内容更加容易了解&#xff0c;当然没有基础的也别担心&#xff0c;本期内容会详细解释有关内容 本期用到的软件&#xff1a;yakit&#xff08;因为经过之前好多期…...

Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决

Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决 问题背景 在一个基于 Spring Cloud Gateway WebFlux 构建的微服务项目中&#xff0c;新增了一个本地验证码接口 /code&#xff0c;使用函数式路由&#xff08;RouterFunction&#xff09;和 Hutool 的 Circle…...

Python 实现 Web 静态服务器(HTTP 协议)

目录 一、在本地启动 HTTP 服务器1. Windows 下安装 node.js1&#xff09;下载安装包2&#xff09;配置环境变量3&#xff09;安装镜像4&#xff09;node.js 的常用命令 2. 安装 http-server 服务3. 使用 http-server 开启服务1&#xff09;使用 http-server2&#xff09;详解 …...

【从零开始学习JVM | 第四篇】类加载器和双亲委派机制(高频面试题)

前言&#xff1a; 双亲委派机制对于面试这块来说非常重要&#xff0c;在实际开发中也是经常遇见需要打破双亲委派的需求&#xff0c;今天我们一起来探索一下什么是双亲委派机制&#xff0c;在此之前我们先介绍一下类的加载器。 目录 ​编辑 前言&#xff1a; 类加载器 1. …...

32单片机——基本定时器

STM32F103有众多的定时器&#xff0c;其中包括2个基本定时器&#xff08;TIM6和TIM7&#xff09;、4个通用定时器&#xff08;TIM2~TIM5&#xff09;、2个高级控制定时器&#xff08;TIM1和TIM8&#xff09;&#xff0c;这些定时器彼此完全独立&#xff0c;不共享任何资源 1、定…...

Vue3中的computer和watch

computed的写法 在页面中 <div>{{ calcNumber }}</div>script中 写法1 常用 import { computed, ref } from vue; let price ref(100);const priceAdd () > { //函数方法 price 1price.value ; }//计算属性 let calcNumber computed(() > {return ${p…...