【Linux】匿名管道实现简单进程池

一、匿名管道通信的四种情况和五种特性

1.1、四种情况

  1. 管道内部没有数据且子进程不关闭自己的写端文件fd,读端(父进程)就要阻塞等待,直到管道里有数据。
  2. 管道内部被写满了且父进程(读端)不关闭自己的读端fd,写端(子进程)写满以后就要阻塞等待。
  3. 对于写端而言,如果写端不写了且关闭了写端fd,读端就会将管道中的数据读完,最后会读到返回值为0,表示读结束,类似于读到了文件的结尾。
  4. 读端关闭了,操作系统就会发送信号直接杀死进行写入的进程,因为没有读端写入也就没有了意义。

1.2、五种特性

  1. 管道自带同步机制,参照上面四种情况中的1,2,3。
  2. 具有血缘关系的进程进行通信,常见于父子。
  3. 管道是面向字节流的。
  4. 父子进程退出,管道自动释放,因为内存中的文件的生命周期是随进程的。 
  5. 管道只能进行单向通信。

二、匿名管道实现简单的进程池

        这个进程池可以分配我们想要的进程的个数,用命令行的方式来控制进程的个数,任务由我们自己定好,每次随机选择一个任务指派给一个进程去完成,进程的选派采用轮询的方式按顺序指派,这其中还有一些实现的细节,会在代码中以注释的方式给出。

头文件

#include <iostream>
#include <string>
#include <unistd.h>
#include <sys/types.h>
#include <vector>
#include <sys/wait.h>
#include <vector>
using namespace std;typedef void (*work_t)(int pipefd);//pipefd为写端文件描述符
typedef void (*task_t)(int pipefd, pid_t fd);//fd为子进程pid//三个任务
void PrintLog(int pipefd, pid_t fd)
{cout <<"pipefd:" << pipefd <<" fd:" << fd <<  " task:printf log task" << endl;
}void ReloadConf(int pipefd, pid_t fd)
{cout <<"pipefd:" << pipefd <<" fd:" << fd <<  " task:Reload Conf" << endl;
}void ConnectMysql(int pipefd, pid_t fd)
{cout <<"pipefd:" << pipefd <<" fd:" << fd <<  " task:Connect Mysql" << endl;
}task_t task[3] = {PrintLog,ReloadConf,ConnectMysql };//随机在三个任务中选择一个
uint32_t nextTask()
{return rand() % 3;
}void worker(int pipefd)
{while(true){uint32_t code = 0;//子进程会阻塞在此读,读到零就证明写端已经关闭了int n = read(0, &code, sizeof(code));if(n == sizeof(code)){if(code >= 3) continue;task[code](pipefd, getpid());sleep(1);}else if(n == 0){cout << "child process quit now!" << endl;break;}}
}

源文件 

#include "processpool.hpp"enum
{UsageError = 1,ArgError,PipeError
};void Usage(char *proc)
{cout << "Usage:" << proc << " num" << endl;
}class Channel
{
private://管道保存写端文件描述符,管道名和子进程pid。int _wfd;string _name;pid_t _processid;public:Channel(int wfd, string name, pid_t id): _wfd(wfd), _name(name), _processid(id){}void print(){cout << "_wfd:" << _wfd << " _name:" << _name << " _processid:" << _processid << endl;}const string name() const{return _name;}const int wfd() const{return _wfd;}const pid_t processid() const{return _processid;}void Close(){close(_wfd);}~Channel(){}
};//进程池
class processPool
{
private:int _sum_child_process;//进程池中进程的个数vector<Channel> _channelVect;public:processPool(int sum_child_process): _sum_child_process(sum_child_process){}// 创建信道和子进程int CreateProcess(work_t work)//任务以函数指针的方式传入{vector<int> fds;for (int i = 0; i < _sum_child_process; i++){//创建匿名管道int pipefd[2];int n = pipe(pipefd);if (n == -1)return PipeError;pid_t id = fork();if (id == 0){//关闭多余的写端描述符,因为父进程在创建子进程的同时会将父进程的文件描述符表也给子进程拷贝一份,//这样子进程的文件描述符表就会保存了之前的子进程的写端文件描述符,必须要把之前的子进程的写端文件描述符关闭,//否则子进程在退出的时候会出异常if (!fds.empty()){for (auto e : fds)close(e);}close(pipefd[1]);dup2(pipefd[0], 0);//输入重定向work(pipefd[0]);exit(0);}string name = "Channel" + to_string(i);close(pipefd[0]);_channelVect.push_back(Channel(pipefd[1], name, id));fds.push_back(pipefd[1]);}return 0;}//发送某个任务给某个管道void SendTaskCode(const Channel *channel, uint32_t code){cout << "send code: " << code << " to " << channel->name() << " sub prorcess id: " << channel->processid() << endl;write(channel->wfd(), &code, sizeof(code));}// 控制子进程void CtrlProcessPool(processPool *processPoolPtr, int cnt)//cnt表示任务的个数{while (cnt){// 1、选择一个进程和信道const Channel *cur = processPoolPtr->nextChannel();cout << cur->name() << endl;// 2、选择一个任务uint32_t n = nextTask();// 派送任务processPoolPtr->SendTaskCode(cur, n);sleep(1);cnt--;}}//按顺序选择一个管道const Channel *nextChannel(){static int n = 0;n %= _sum_child_process;return &_channelVect[n++];}void Print(){for (auto &channel : _channelVect){channel.print();}}// 退出所有子进程void killAll(){for (auto &Channel : _channelVect){Channel.Close();pid_t rid = Channel.processid();pid_t quitid = waitpid(rid, nullptr, 0);if (rid == quitid)cout << rid << " quit succeed!" << endl;}}   ~processPool(){}
};int main(int argc, char *argv[])
{if (argc != 2){Usage(argv[0]);return ArgError;}// 创建信道和子进程int sum_child_process = stoi(argv[1]);processPool *processPoolPtr = new processPool(sum_child_process);// vector<Channel> channelVect;processPoolPtr->CreateProcess(worker);srand(time(nullptr));// 控制子进程int cnt = 10;//10个任务processPoolPtr->CtrlProcessPool(processPoolPtr, cnt);// 回收子进程processPoolPtr->killAll();//processPoolPtr->Wait();delete processPoolPtr;return 0;
}

makefile

myprocesspool:processpool.ccg++ -o $@ $^
.PHONY:clean
clean:rm -f myprocesspool

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

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

相关文章

kali工具----网络映射器(Network Mapper)系统指纹

系统指纹识别 现在一些便携式计算机操作系统使用指纹识别来验证密码进行登录。指纹识别是识别系统的一个典型模式&#xff0c;包括指纹图像获取、处理、特征提取和对等模块。如果要做渗透测试&#xff0c;需要了解要渗透测试的操作系统的类型才可以。本节将介绍使用Nmap工具测试…

【OTA】STM32-OTA升级——持续更新

【OTA】STM32-OTA升级——持续更新 文章目录 前言一、ymodem串口协议1、Ymodem 协议2、PC3、蓝牙4、WIFI云平台 二、UDS车载协议1.UDS协议 总结 前言 提示&#xff1a;以下是本篇文章正文内容&#xff0c;下面案例可供参考 一、ymodem串口协议 1、Ymodem 协议 STM32 Ymodem …

【第三十篇】并发插件 turbo intruder 安装及使用教程

文章目录 安装使用本篇主要介绍turbo intruder的两种安装方式及使用教程。 安装 1、在BurpSuite的扩展模块的BAPP商店中找到turbo intruder,点击安装即可使用: 2、若在BurpSuite中无法直接安装,可手动添加该插件。 具体操作: 进入Github中安装: https://github.com/Po…

代码随想录算法训练营三刷day53 | 动态规划之子序列 1143.最长公共子序列 1035.不相交的线 53. 最大子序和

day53 1143.最长公共子序列1.确定dp数组&#xff08;dp table&#xff09;以及下标的含义2.确定递推公式3.dp数组如何初始化4.确定遍历顺序5.举例推导dp数组 1035.不相交的线53. 最大子序和1.确定dp数组&#xff08;dp table&#xff09;以及下标的含义2.确定递推公式3.dp数组如…

伺服系统中对于前馈算法的一点理解

前馈是指根据指令的偏差控制&#xff0c;当一个系统处在跟随误差较大的运动阶段时&#xff08;运行速度较快&#xff09;&#xff0c;可以加入前馈环节&#xff0c;有助于提高响应速度和改善轨迹控制中的拐角处的工艺特性。 前馈控制主要应用于该控制系统本身存在较大的滞后作用…

全量知识系统 程序详细设计之 统一资产模型(QA百度文库 )

Q1. 在设计的全知系统中&#xff0c;矩阵表示的是“活物”&#xff0c;分别 类似 一个基因的活性、一个实体的辨识度和某种特征的可区分度。 函数的可微、可积和可导性 则表示 运动的控制方式 在您所设计的全知系统中&#xff0c;将矩阵与“活物”的属性&#xff08;如基因的活…

FireProx:一款功能强大的AWS API网关管理与IP地址轮换代理工具

关于FireProx FireProx是一款功能强大的AWS API网关安全管理工具&#xff0c;该工具可以帮助广大研究人员创建实现唯一IP地址轮换的实时HTTP转发代理。 在发送网络请求或进行网络交互时&#xff0c;实现源IP地址轮换是一个非常复杂的过程&#xff0c;虽然社区中也有相关的工具…

【STL详解 —— stack和queue的介绍及使用】

STL详解 —— stack和queue的介绍及使用 stackstack的定义方式stack的使用 queuequeue的定义方式queue的使用 stack stack是一种容器适配器&#xff0c;专门用在具有后进先出操作的上下文环境中&#xff0c;其只能从容器的一端进行元素的插入与提取操作。 stack的定义方式 首…

前端三剑客 —— JavaScript (第六节)

目录 内容回顾 BOM编程 DOM编程* document对象 document对象的属性 document对象的方法 DOM对象节点 操作DOM对象内容 操作DOM对象的属性 --- DOM对象.属性名称 --- DOM对象[属性名称] --- 调用系统API &#xff08;Application Program interface&#xff09;&#…

Linux登录访问限制

Linux系统下&#xff0c;用户密码的有效期可以通过编辑/etc/login.defs文件控制&#xff1b;密码复杂度规则设定需要通过/etc/pam.d/system-auth文件控制&#xff1b;登录失败次数限制通常由/etc/pam.d/login文件限制&#xff0c;可使用pam_tally2模块进行设置。 Linux系统下的…

代码随想录-算法训练营day09【字符串02:KMP、重复的子字符串、字符串总结、双指针回顾】

代码随想录-035期-算法训练营【博客笔记汇总表】-CSDN博客 第四章 字符串part02 今日任务 ●28. 实现 strStr() ●459.重复的子字符串 ●字符串总结 ●双指针回顾 详细布置 28. 实现 strStr() &#xff08;本题可以跳过&#xff09;因为KMP算法很难&#xff0c;大家别奢求 一…

爬虫 | 网易新闻热点数据的获取与保存

Hi&#xff0c;大家好&#xff0c;我是半亩花海。本项目是一个简单的网络爬虫&#xff0c;用于从网易新闻的热点新闻列表中提取标题和对应的链接&#xff0c;并将提取到的数据保存到一个 CSV 文件中。 目录 一、技术栈 二、功能说明 三、注意事项 四、代码解析 1. 导入所需…

Playwright安装和基本使用(ui/web自动化)

1.简介 Playwright是2021年微软开源的一个项目「playwright-python」。针对 Python 语言的纯自动化工具&#xff0c;它可以通过单个API自动执行 Chromium&#xff0c;Firefox 和 WebKit 浏览器&#xff0c;同时支持以无头模式、有头模式运行。 Playwright&#xff08;Git&…

springboot汽车企业公司网站的系统设计ssm-java

框架&#xff1a;SSM/springboot都有 jdk版本&#xff1a;1.8 及以上 ide工具&#xff1a;IDEA 或者eclipse 数据库: mysql 编程语言: java 前端&#xff1a;layuibootstrapjsp 详细技术&#xff1a;HTMLCSSJSjspspringmvcmybatisMYSQLMAVENtomcat 开发工具 IntelliJ IDEA: 一…

【学习】软件测试人员使用Loadrunner进行性能测试的优势

在软件测试领域&#xff0c;性能测试是一项至关重要的环节&#xff0c;它关乎到软件系统的稳定性和用户体验。而在这其中&#xff0c;Loadrunner作为一款久经考验的性能测试工具&#xff0c;凭借其独特的优势&#xff0c;成为了众多企业和开发者眼中的“得力助手”。 首先&…

1036: 寻找整数序列的主元素

解法&#xff1a; #include<iostream> #include<vector> #include<algorithm> using namespace std; int main() {int n;cin >> n;vector<int> arr(n);vector<int> tong(1000);for (auto& x : arr) {cin >> x;tong[x];}int pma…

Guava里一些比较常用的工具

随着java版本的更新提供了越来越多的语法和工具来简化日常开发&#xff0c;但是我们一般用的比较早的版本所以体验不到。这时就用到了guava这个包。guava提供了很多方便的工具方法&#xff0c;solar框架就依赖了guava的16.0.1版本&#xff0c;这里稍微介绍下。 一、集合工具类…

vue3 uniapp微信登录

根据最新的微信小程序官方的规定&#xff0c;uniapp中的uni.getUserInfo方法不再返回用户头像和昵称、以及手机号 首先&#xff0c;需获取appID&#xff0c;appSecret&#xff0c;如下图 先调用uni.getUserInfo方法获取code&#xff0c;然后调用后台的api&#xff0c;传入code&…

大模型项目整体规划、技术选型和案例分析经验分享

1 项目整体规划 1.1 明确场景 toB or toC&#xff08;面向企业还是面向消费者&#xff09; toB&#xff08;面向企业&#xff09;&#xff1a;指的是产品或服务主要面向其他企业或组织。这类产品通常需要解决特定的商业问题&#xff0c;强调效率和集成性&#xff0c;并且可能需…

什么是 MVVM、mvc 模型

mvc模型 MVC: MVC 即 model-view-controller&#xff08;模型-视图-控制器)是项目的一种分层架构思想&#xff0c;它把复杂的业务逻辑&#xff0c; 抽离为职能单一的小模块&#xff0c;每个模块看似相互独立&#xff0c;其实又各自有相互依赖关系。它的好处是&#xff1a;保证了…