简易进程池的实现

news2024/11/25 23:01:45

什么是进程池?

        进程池(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;
            else
            cout<<"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.coloradmin.cn/o/1694017.html

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

相关文章

同名在线查询系统微信小程序源码下载支持多种流量主,附带系统教程

同名在线查询系统微信小程序源码下载支持多种流量主这是一款支持查询同名的一款微信小程序 该款小程序支持多种查询模式 重名查询&#xff0c;热度查询&#xff0c;概率香查询 源码免费下载地址抄笔记(chaobiji.cn)

LaTex 模板 - 东北师范大学申研申博推荐信

文章目录 NENU-Letter-Template项目地址示例特性项目结构如何使用main.texletterContent.tex 如何编译方式 1 &#xff1a;在线编译方式 2 &#xff1a;本地编译 参考 NENU-Letter-Template NENU’s recommendation letter template. 东北师范大学推荐信模板 项目地址 GitHu…

Linux驱动设备导论(1)

最近本人在学习Linux驱动&#xff0c;本系列教程是本人在一边学习&#xff0c;一边总结的系列教程&#xff0c;希望能够给很多刚学驱动小伙伴一些总结。 1.Linux设备分类 驱动针对的对象是存储器和外设&#xff0c;不是针对CPU&#xff0c;可以分为以下三大类&#xff1a; 1.…

WordPress Country State City Dropdown CF7插件 SQL注入漏洞复现(CVE-2024-3495)

0x01 产品简介 Country State City Dropdown CF7插件是一个功能强大、易于使用的WordPress插件,它为用户在联系表单中提供国家、州/省和城市的三级下拉菜单功能,帮助用户更准确地填写地区信息。同时,插件的团队和支持也非常出色,为用户提供高质量的服务。 0x02 漏洞概述 …

统计信号处理基础 习题解答10-4

题目&#xff1a; 重复习题10.3&#xff0c;但条件PDF变为&#xff1a; 以及均匀先验。如果非常大&#xff0c;这样先验知识很少&#xff0c;则会出现什么情况。 解答&#xff1a; 如果记 那么&#xff0c;根据条件独立性质&#xff0c;得到&#xff1a; 其中&#xff0c;&am…

蛮力法0/1背包问题实验

实验项目1 蛮力法 实验题目 使用蛮力法解决0/1背包问题。 ​ 问题描述&#xff1a;给定n个重量(weight)为{w1, w2, … ,wn}、价值(key)为{v1, v2, … ,vn}的物品和一个**容量为C(contain)**的背包&#xff0c;求这些物品中的一个最有价值的子集&#xff0c;且要能够装到背包中…

【活动】开源与闭源大模型:探索未来趋势的双轨道路

&#x1f308;个人主页: 鑫宝Code &#x1f525;热门专栏: 闲话杂谈&#xff5c; 炫酷HTML | JavaScript基础 ​&#x1f4ab;个人格言: "如无必要&#xff0c;勿增实体" 文章目录 开源与闭源大模型&#xff1a;探索未来趋势的双轨道路引言一、开源大模型&#…

搭建访问阿里云百炼大模型环境

最近这波大降价&#xff0c;还有限时免费&#xff0c;还不赶快试试在线大模型&#xff1f;下面整理访问百炼平台的千问模型方法。 创建RAM子账号并授权 创建RAM子账号 1. “访问控制RAM”入口&#xff08;控制台URL&#xff09; 然后点击进入“RAM管理控制台” 2. 添加用户 …

ASP+ACCESS多功能论坛程序设计

摘 要 随着计算机的广泛应用&#xff0c;人们已经对网络不再感到陌生。在科技飞速发展的今天&#xff0c;电脑信息技术与各行各业进行了有效的结合。人们在网上可以进行网上购物&#xff0c;网上交友&#xff0c;电子商务&#xff0c;网络营效等等。面对强大的网络功能&#x…

使用nvm管理nodejs多个版本

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

C++完成特色旅游管理信息系统

背景&#xff1a; 继C完成淄博烧烤节管理系统后&#xff0c;我们来到了特色旅游管理信息系统的代码编写&#xff0c;历史链接点下方。 C完成淄博烧烤节管理系统_淄博烧烤总账管理系统的-CSDN博客 问题描述&#xff1a; 为了更好的管理各个服务小组&#xff0c;开发相应的管…

学会这些大模型术语,你可以硬控朋友7.13分钟

你对于大型语言模型&#xff08;LLMs&#xff09;的复杂世界以及围绕它们的技术术语感到好奇吗&#xff1f; 理解从训练和微调的基础方面到转换器和强化学习的尖端概念&#xff0c;是揭开驱动现代人工智能大语言模型神秘面纱的第一步。 在本文中&#xff0c;我们将深入探讨 25 …

基于DdddOcr通用验证码离线本地识别SDK搭建个人云打码接口Api

前言 最近介绍了一款免费的验证码识别网站,识别效率太低,考虑到ddddocr是开源的,决定搭建搭建一个,发现原作者sml2h3已经推出好久了,但是网上没有宝塔安装的教程,于是本次通过宝塔搭建属于自己的带带弟弟OCR通用验证码离线本地识别 原项目地址:https://github.com/sml2…

m1系列芯片aarch64架构使用docker-compose安装rocketmq5.0以及运维控制台

之前看到 DockerHub 上有大佬制作了 m1 芯片, aarch64架构的 rocketmq 镜像, 所以就尝试的安装了下, 亲测可用: 一. docker-compose.yml 文件命令 volumes 挂载目录需要换成自己的目录 注意 depends_on 标签, broker 和 console 的 启动要晚于 namesrv, 因为 broker 需要注册…

CentOS 7.9安装NVIDIA P40显卡驱动、CUDA和cuDNN

文章目录 1、安装P40显卡驱动1.1 查看机器上有哪些显卡1.2 禁用nouveau1.3 安装依赖1.4 安装驱动 2、安装CUDA2.1 安装2.2 测试是否安装成功 3、安装cuDNN3.1 安装3.2 测试是否安装成功 4、总结 1、安装P40显卡驱动 1.1 查看机器上有哪些显卡 lspci | grep -i vga lspci | gr…

全局平均池化笔记

全局平均池化&#xff08;Global Average Pooling, GAP&#xff09;是一种用于卷积神经网络&#xff08;CNN&#xff09;中的池化操作&#xff0c;其主要作用和优点包括&#xff1a; 减少参数数量&#xff1a;全局平均池化层将每个特征图通过取其所有元素的平均值&#xff0c;压…

pytorch深度学习-环境搭建

1.Anaconda下载&#xff08;首先安装Anaconda不需要先安装Python了&#xff01;&#xff09; 版本 3.11. Download Anaconda Distribution | Anaconda 1.2 跳过注册直接下载 2.安装 直接next, (Install for 可以选择All Users&#xff0c;我选择的是All Users) 点击默认选项…

ROS学习记录:用C++实现IMU航向锁定

前言 获取IMU数据的C节点 在了解了如何获取到IMU的姿态信息&#xff08;链接在上面&#xff09;后&#xff0c;接下来尝试实现让一个节点在订阅IMU数据的时候&#xff0c;还能发布运动控制指令&#xff0c;使机器人能对姿态变化做出反应&#xff0c;达到一个航向锁定的效果。 …

MacBook 怎么玩Windows游戏 苹果笔记本怎么玩游戏?mac上如何玩windows游戏

传统上&#xff0c;Mac 不被认为是好的游戏机。然而&#xff0c;苹果已经开始在 Mac 上的游戏上投入更多精力&#xff0c;特别是自从转向苹果芯片以来。这使得 Mac 游戏的本机移植数量和模拟 Windows 游戏的能力都得到了显著提高。 方法一&#xff1a;Boot Camp 1、Boot Camp是…

K8S集群中Yaml文件详解

目录 一、Yaml概述 二、Yaml基本语法 三、Yaml数据结构 四、K8S资源清单描述方法 五、api资源版本标签 六、Yaml文件示例详解 1.deployment.yaml文件详解 2.Pod yaml文件详解 3.Service yaml文件详解 七、Yaml文件相关操作 1.试运行 2.生成yaml格式 3.生成json格式…