简易进程池的实现

什么是进程池?

        进程池(Process Pool)是一种用于管理和复用多个进程的技术或设计模式。在进程池中,一定数量的进程会被预先创建并保持在内存中,以便在需要时立即使用,而不是每次需要进程时都重新创建新的进程,这样可以提高系统的性能和效率。

        进程池通常用于需要频繁创建和销毁进程的场景,例如网络服务器等。通过预先创建一些进程并保持它们处于空闲状态,可以避免频繁创建和销毁进程所带来的开销,并且可以更好地控制同时进行的进程数量,以避免系统资源被耗尽。

        一般来说,进程池包括以下几个基本组件:
1. 进程池管理器(Process Pool Manager):负责创建、管理和维护进程池中的进程,包括池中进程的初始化、分配和回收等操作。
2. 进程队列(Process Queue):用于存放空闲进程的队列,当有任务需要处理时,可以从队列中取出一个空闲进程进行任务处理。
3. 任务队列(Task Queue):用于存放需要处理的任务,当一个进程空闲时,可以从任务队列中取出一个任务进行处理。
4. 进程间通信机制:用于进程之间的通信,例如管道、共享内存、消息队列等。

通过合理设计和使用进程池,可以提高系统的并发处理能力,降低系统资源消耗,同时也便于监控和管理进程。

以下是我们的简易进程池的框架。 

 

因此在本次项目中,在面向对象思想的指导下,我们需要创建一个进程池,管理进程的相关操作。

思路 

我们在写之前,首先需要明确项目的功能是什么?都需要实现哪些模块?

将大框架搭建好之后,逐步填充细节。

首先我们明确需要实现的功能是:一个父进程开辟进程池中的多个子进程,然后向子进程发送任务信息,由子进程执行任务。

实现的模块:进程池(包含子进程的创建,子进程的执行任务板块,子进程的销毁),任务模块,父进程控制块。

我们可以将进程封装为一个小类,再用进程池封装进程的类。利用匿名管道的特性实现父子进程间通信。 

需要注意进程与任务间的负载均衡。

一个超级大Bug 

我们知道,子进程是会继承父进程的文件信息列表的,因此当父进程以写端打开管道,其后创建的子进程将会继承当前父进程的所有wfd与rfd,但由于父进程rfd个数为0,但wfd会叠加,因此最后一个子进程将会继承前面父进程的所有wfd。也就是说,后面创建的进程,会保存前面创建的管道的写文件描述符。 因此倘若我们按从前往后的顺序关闭父进程写端同时进行wait等待,是没有结果的。

我们的解决方法是每创建一个子进程,都会关闭其从父进程那里继承来的所有写文件描述符。

当然也有别的办法,1.从后往前关闭管道,最后的管道只有父进程一个写端。

2. 将所有的写端全部结束之后再进行wait等待。

源码 

task.hpp 

任务模块,其内包含任务列表,与工作过程 

#pragma once
#include<iostream>
#include<unistd.h>
using namespace std;typedef void (*work_t)(int);//函数指针类型
typedef void(*task_t)();void task1()
{cout<<"i'm task11111, hello people! from sub process: "<<getpid()<<endl;
}void task2()
{cout<<"i'm task22222, hello people! from sub process: "<<getpid()<<endl;
}void task3()
{cout<<"i'm task33333, hello people! from sub process: "<<getpid()<<endl;
}//任务的函数指针数组,存储任务列表
task_t taskarray[]={task1,task2,task3};//寻找下一个派发的任务
int NextTask()
{//随机抽取任务return rand()%3;
}//工作过程
void worker(int rfd)
{while(true){sleep(1);int taskcode=0;//接收任务码int n=read(rfd,&taskcode,sizeof(taskcode));//当可以读取到任务信息执行任务if(n==sizeof(taskcode)){//执行任务taskarray[taskcode]();cout<<"task success excute... processid: "<<getpid()<<endl<<endl;}else//读取不到任务信息即退出{cout<<"no task can excute,exit...  processid: "<<getpid()<<endl<<endl;break;}}}

processpool.cc 

完成进程池的创建,销毁与回收等待,同时保证任务的正确执行与退出。 

#include<iostream>
#include<string>
#include<vector>
#include<sys/types.h>
#include<sys/wait.h>
#include<unistd.h>
#include"task.hpp"
using namespace std;//管理管道属性
class channel
{
public:channel(size_t wfd,size_t pid,string name):_wfd(wfd),_process_id(pid),_channel_name(name){}size_t wfd(){return _wfd;}size_t pid(){return _process_id;}string name(){return _channel_name;}void Close(){close(_wfd);}~channel(){}private:size_t _wfd;size_t _process_id;string _channel_name;
};//管理进程池
class processpool
{
public:processpool(int sub_process_num):_sub_process_num(sub_process_num){}//创建进程池void CreatProcessPool(work_t worker){for(int i=0;i<_sub_process_num;i++)//创建管道与进程{int pipefd[2];pipe(pipefd);pid_t pid=fork();vector<int> fds;//存放管道中除却父进程以外的写端,并在子进程中一一进行释放if(pid==0)//子进程读{close(pipefd[1]);for(int i=0;i<fds.size();i++){close(fds[i]);}//子进程接收父进程发送的任务并完成任务worker(pipefd[0]);exit(0);}//父进程为写端close(pipefd[0]);string name="channel-";name+=to_string(pid);_channels.push_back(channel(pipefd[1],pid,name));fds.push_back(pipefd[1]);//将父进程的wfd进行插入,当下一个子进程创建后会继承该文件信息//因此在子进程中需要关闭继承到的写端,以免管道出现多个写端的状况//多个写端造成后果,当父进程终止写入,管道仍旧有多个管道//父进程发送任务给子进程}}void PrintDebug()//打印进程池中进程相关信息{for(auto &e: _channels){cout<<"_wfd: "<<e.wfd()<<"\t";cout<<"_process_pid: "<<e.pid()<<"\t";cout<<"_channel_name: "<<e.name()<<"\t";cout<<endl;}}//寻找下一个分配任务的子进程int NextChannel(){static int cnt=0;int ret=cnt%_channels.size();cnt++;return ret;}//发送任务信息码给子进程void SendTaskMessage(int index,int taskcode){cout<<"taskcode:"<<taskcode<<"  channel id: "<<_channels[index].pid()<<endl;int n=write(_channels[index].wfd(),&taskcode,sizeof(taskcode));}//杀死进程池中所有子进程void KillAll(){for(int i=0;i<_channels.size();i++){_channels[i].Close();}}//对所有子进程进行回收void Wait(){for(int i=0;i<_channels.size();i++){pid_t pid=_channels[i].pid();int ret=waitpid(pid,nullptr,0);if(ret=pid)cout<<"sub process already recyle success... processid: "<<pid<<endl;elsecout<<"sub process already recyle fail fail fail!!!  processid: "<<pid<<endl;}}
private:int _sub_process_num;vector<channel> _channels;
};//控制进程池执行任务
void CtrlProcessPool(processpool Processpool,int cnt)
{while(cnt-->0){//挑选进程int index=Processpool.NextChannel();//挑选任务int taskcode=NextTask();//发送任务给进程sleep(1);cout<<"第"<<cnt<<"个任务"<<endl;Processpool.SendTaskMessage(index,taskcode);}
}
int main(int argc,char* argv[])
{if(argc!=2)//规范启动法则{cout<<"Please Re-Enter!  Please enter subprocess numbers!"<<endl;return -1;}//启动成功int subprocess_num=stoi(argv[1]);//创建进程池processpool Processpool(subprocess_num);Processpool.CreatProcessPool(worker);//Processpool.PrintDebug();//控制子进程//挑选进程与任务,并将任务发送给对应进程CtrlProcessPool(Processpool,7);//结束后回收子进程//关闭写端,进而关闭子进程Processpool.KillAll();//父进程等待回收子进程Processpool.Wait();return 0;
}

代码中有详细注释。 

运行结果 

 

这里的任务与进程是整数倍的关系,因此显得比较规整。 

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

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

相关文章

每日一题《leetcode--1472.设计浏览器历史记录》

https://leetcode.cn/problems/design-browser-history/ 这里我是用双栈实现前进和后退。 #define URL_SIZE 21 #define STACK_SIZE 5000typedef struct {char *BackStack[STACK_SIZE]; //回退栈char *ForwardStack[STACK_SIZE]; //前进栈int BackTop; //回退栈的栈顶下标…

Kubectl 的使用——k8s陈述式资源管理

一、kebuctl简介: kubectl 是官方的CLI命令行工具&#xff0c;用于与 apiserver 进行通信&#xff0c;将用户在命令行输入的命令&#xff0c;组织并转化为 apiserver 能识别的信息&#xff0c;进而实现管理 k8s 各种资源的一种有效途径。 对资源的增、删、查操作比较方便&…

使用nvm管理nodejs多个版本

在工作中&#xff0c;可能会遇到同时使用vue2和vue3开发项目&#xff0c;但他们的nodejs版本又不同&#xff0c;给你带来了困扰&#xff0c;不知道怎么办&#xff1f;这时就可以使用nvm管理多个nodejs版本 第一步&#xff1a;先去github上面下载nvm 这是下载地址&#xff1a;…

Fastjson漏洞之CVE-2017-18349

前言&#xff1a; 要想理解漏洞原理&#xff0c;首先看看Fastjson是什么&#xff0c;具体用来做什么才能更好的找到可以利用的场景&#xff1a; Fastjson 是一个由阿里巴巴开发的 Java 语言实现的高性能 JSON 解析器和生成器。它具有以下特点: 快速&#xff1a;Fastjson 在序列…

《我的阿勒泰》读后感

暂没时间写&#xff0c;记录在此&#xff0c;防止忘记&#xff0c;后面补上!!! 【经典语录】 01、如果天气好的话&#xff0c;阳光广阔地照耀着世界&#xff0c;暖洋洋又懒洋洋。这样的阳光下&#xff0c;似乎脚下的每一株草都和我一样&#xff0c;也把身子完全舒展开了。 02、…

OpenHarmony 实战开发——一文总结ACE代码框架

一、前言 ACE_Engine框架是OpenAtom OpenHarmony&#xff08;简称“OpenHarmony”&#xff09;的UI开发框架&#xff0c;为开发者提供在进行应用UI开发时所必需的各种组件&#xff0c;以及定义这些组件的属性、样式、事件及方法&#xff0c;通过这些组件可以方便进行OpenHarmo…

输入输出(3)——C++的标准输入流

目录 一、cin 流 二、成员函数 get 获取一个字符 (一)无参数的get函数。 (二)有一个参数的get函数。 (三&#xff09;有3个参数的get函数 (四&#xff09;用成员函数 getline 函数读取一行字符 (五&#xff09;用成员函数 read 读取一串字符 (六&#xff09;istream 类…

HACL-Net:基于MRI的胎盘植入谱诊断的分层注意力和对比学习网络

文章目录 HACL-Net: Hierarchical Attention and Contrastive Learning Network for MRI-Based Placenta Accreta Spectrum Diagnosis摘要方法实验结果 HACL-Net: Hierarchical Attention and Contrastive Learning Network for MRI-Based Placenta Accreta Spectrum Diagnosis…

NXP i.MX8系列平台开发讲解 - 3.12 Linux 之Audio子系统(一)

专栏文章目录传送门&#xff1a;返回专栏目录 目录 1. Audio 基础介绍 1.1 音频信号 1.2 音频的处理过程 1.3 音频硬件接口 1.3 音频专业术语解释 2. Linux Audio子系统介绍 3. Linux Audio子系统框架 Linux嵌入式系统中的音频子系统扮演着至关重要的角色&#xff0c;它涉…

爬虫案例-亚马逊反爬流程分析梳理(验证码突破)(x-amz-captcha)

总体概览&#xff1a;核心主要是需要突破该网站的验证码&#xff0c;成功后会返回我们需要的参数后再去请求一个中间页&#xff08;类似在后台注册一个session&#xff09;&#xff0c;最后需要注意一下 IP 是不能随意切换的 主要难点&#xff1a; 1、梳理整体反爬流程 2、验证…

哥白尼哨兵系列卫星数据不能下载的解决方法

自2023年1月24日起&#xff0c;一个新的哥白尼数据空间生态系统已经启动&#xff0c;为所有哨兵数据&#xff08;Sentinel-1, Sentinel-2, Sentinel-3 and Sentinel-5P&#xff09;提供可视化和数据处理&#xff0c;地址为&#xff1a;https://dataspace.copernicus.eu/。详细介…

算法刷题笔记 高精度乘法(C++实现)

文章目录 题目描述解题思路解题代码 题目描述 给定两个非负整数&#xff08;不含前导0&#xff09;A和B&#xff0c;请你计算 AB的值。 输入格式 共两行&#xff0c;第一行包含整数 A&#xff0c;第二行包含整数 B。 输出格式 共一行&#xff0c;包含AB的值。 数据范围 …

world machine学习笔记(3)

打开 可以打开场景设置&#xff0c;项目设置平铺构建设置 场景设置&#xff1a; 输出范围 设置中心点和范围 设置分辨率 项目设置&#xff1a; 设置地图颜色&#xff0c;单位&#xff0c;最高地形高度 点击这个图形进行预览设置 该按钮还有其他的功能 world machine基础流程…

知识分享:大数据信用花导致的评分不足多久能恢复

随着金融风控领域越来越科技化&#xff0c;基于大数据技术的金融风控成为了贷前风控不可或缺的重要环节&#xff0c;相信很多人在申贷的时候都听说过大数据信用和综合评分等词语&#xff0c;那大数据信用花导致的评分不足多久能恢复呢?本文带大家一起去了解一下。 首先&#x…

【AI大模型】这可能是最简单的本地大模型工具,无须部署,一键使用

目录 前言 LM-Studio​编辑 那么问题来了&#xff0c;为什么我要在本地部署大模型&#xff1f; 隐私性&#xff1a; 定制性&#xff1a; 成本和体验的优化&#xff1a; 工具功能特点和使用方式介绍&#xff1a; 首页提供搜索功能和一些模型的推荐 模型下载管理&#x…

【Python】 探索Python中的整数最大值和最小值

基本原理 在Python中&#xff0c;整数&#xff08;int&#xff09;类型是一种基本数据类型&#xff0c;用于表示整数。Python的整数类型是动态的&#xff0c;这意味着它们可以自动扩展以存储非常大的数值。然而&#xff0c;尽管Python的整数可以非常大&#xff0c;但它们仍然有…

使用VirtualBox+vagrant创建CentOS7虚拟机

1.VirtualBox 1.1.什么是VirtualBox VirtualBox 是一款开源虚拟机软件。VirtualBox 是由德国 Innotek 公司开发&#xff0c;由Sun Microsystems公司出品的软件&#xff0c;使用Qt编写&#xff0c;在 Sun 被 Oracle 收购后正式更名成 Oracle VM VirtualBox。 1.2.下载Virtual…

【Kafka】消息的顺序性、可靠性、幂等性

目录 消息顺序性消息可靠性生产者丢失消息消费者丢失消息Kafka丢失消息 消息幂等性 消息顺序性 消息追加到partition尾部&#xff0c;单个partition是有序的&#xff0c;但多个partition如何进行有序的获取一些消息&#xff1f; 解决方案 一个topic只设置一个partition&…

驱动执行报“Attribute var: Invalid permissions 0665”

问题&#xff1a;执行驱动的时候会报下面这个错误 WARNING: CPU: 0 PID: 123 at fs/sysfs/group.c:61 internal_create_group0x170/0x264() Attribute var: Invalid permissions 0665 问题分析&#xff1a;查看 fs/sysfs/group.c:61的代码&#xff0c;发现是我设置 module_par…

数组-在两个长度相等的有序数组中找到上中位数

题目描述 解题思路 此题目直接遍历两个列表&#xff0c;时间复杂度为O(n)&#xff1b;使用二分法去比较两个递增列表的中位数&#xff0c;缩小两个数组中位数范围&#xff0c;时间复杂度O(logn)&#xff0c;这里我们的算法实现使用二分法。 通过举例子来说明解题算法&#xf…