Linux--进程池

这次,我们来写一个线程池的非常简陋代码,帮助我们理解

我们之前也讲到过:关于C++的池化技术。

进程池是预先创建一组子进程,统一管理任务分配与资源回收的并发模型

什么是进程池?

进程池是预先创建一组空闲进程,统一管理任务队列,避免频繁创建/销毁线程开销的并发编程模型
思路是:

利用父进程管理所有的子进程,而让子进程去完成某种任务!

我们通过匿名管道来实现:

父进程传输信息给子进程,子进程根据父进程传输的信息来执行不同的任务!

简单来说就是:父进程发出指令,由子进程去执行

为什么进程池能够提高效率?

因为OS不相信用户,因此,我们的执行任务的代码中,必定会由大量的系统调用来构成,而上几篇我们讲到,它调用是有成本的!

现在我们采用:预先创建进程,要用时直接拿,而不是需要用到是再去创建进程。同时,在执行完一个任务的子进程还可以继续去执行另外的任务,从而用重复利用的方法提高了资源效率。

我们知道:管理好事物的本质就是:"先描述,在组织!"

创建对象结构体:

复制代码
class channel
{
public:
    channel(int comfd, pid_t slaverid, std::string processname)
        : _comdfd(comfd), _slaverid(slaverid), _processname(processname)
    {
    }
    // private:
public:
    int _comdfd;              // 发送任务的文件描述符
    pid_t _slaverid;          // 子进程的pid
    std::string _processname; // 子进程的名字,方便打日志
};

我们操作流程主要有:

初始化

控制进程

关闭进程

复制代码
int main()
{
    //模拟执行任务
    LoadTask(&tasks);
    //种下随机数种子
    srand(time(nullptr));
    // 再组织
    std::vector<channel> channels;
    // 初始化,创建多个进程,建立框架!
    InitSliver(&channels);
    // Debug(channels);
    // std::cout<<channels[0]._comdfd<<":"<<channels[0]._slaverid<<":"<<channels[0]._processname<<std::endl;
    //控制进程
    ctrlSlaver(channels);
    QuitSlaver(channels);
    return 0;
}

模拟执行任务:

复制代码
#pragma once
#include<iostream>
#include<vector>

//自定义函数指针
typedef void(*task_t)();

void Task1()
{
    std::cout<<"检查单词是否有问题"<<std::endl;
}

void Task2()
{
    std::cout<<"检查是否要更新版本"<<std::endl;
}

void Task3()
{
    std::cout<<"查看下载进度"<<std::endl;
}

void Task4()
{
    std::cout<<"查看用户是否需要登录"<<std::endl;
}

void LoadTask(std::vector<task_t>* tasks)
{
    tasks->push_back(Task1);
    tasks->push_back(Task2);
    tasks->push_back(Task3);
    tasks->push_back(Task4);

进程执行任务

复制代码
void sliver()
{
    while(true)
    {
        int cmdcode=0;
        //读取到cmdcode中
        int n=read(0,&cmdcode,sizeof(int));
        if(n==sizeof(int))
        {
            std::cout<<"slaver get a command: "<<getpid()<<" comdcode:"<<cmdcode<<std::endl;
            if(cmdcode>=0 &&cmdcode<tasks.size())
            {
                tasks[cmdcode]();
            }
        }
        if(n==0)
            break;
    }
}

初始化部分

复制代码
//输出型参数 *
//输入型参数const &
//输入输出型参数 &
void InitSliver(std::vector<channel>* channels)
{
    //确保每一个子进程都只有一个写端
    std::vector<int>oldfd;
    for (int i = 0; i < 10; i++)
    {
        int pipefd[2];
        // 建立管道
        int n = pipe(pipefd);
        if (n < 0)
        {
            perror("pipe");
            return;
        }
        // 创建父子进程
        pid_t id = fork();
        if (id < 0)
        {
            perror("fork");
            return;
        }
        else if (id == 0) // child
        {
            for(auto&fd:oldfd)
                close(fd);
            close(pipefd[1]); // 关闭一端
            dup2(pipefd[0], 0);
         
            close(pipefd[0]);
            sliver();
            std::cout<<"process: "<<getpid()<<" quit"<<std::endl;
            exit(0);
            
        }
        // father
        
            close(pipefd[0]); // 关闭一端
            std::string processname = "process" + std::to_string(i);
            channels->push_back({pipefd[1], id, processname});
            oldfd.push_back(pipefd[1]);
            
            // sleep(1);
    }
    
}

简洁菜单:

复制代码
void Menu()
{
    std::cout << "####################################################################" << std::endl;
    std::cout << "####################################################################" << std::endl;
    std::cout << "#######1.检查单词是否有问题    2.检查是否要更新版本###################" << std::endl;
    std::cout << "#######3. 查看下载进度   4.查看用户是否需要登录#######################" << std::endl;
    std::cout << "##########0.退出####################################################" << std::endl;
    std::cout << "####################################################################" << std::endl;
} 

控制进程模块:

复制代码
void ctrlSlaver(const std::vector<channel>& channels)
{
    int count=0;
    while(true)
    {
        int select=0;
        Menu();
        std::cout<<"Please Enter# "<<std::endl;
        std::cin>>select;

        if(select<=0 ||select>5)
            break;
        
        //选择任务
        // int cmdcode=rand()%tasks.size();
        int cmdcode=select-1;
        //选择进程
        int processpos=rand()%tasks.size();
        std::cout<<"father say:"<<"cmdcode:"<<cmdcode<<" already send to "<<channels[processpos]._slaverid<<
            " process name: "<<channels[processpos]._processname<<std::endl;
        //发送任务
        write(channels[processpos]._comdfd,&cmdcode,sizeof(cmdcode));
        count++;
        if(count>=5)
            break;
        sleep(1);
    }

}

关闭进程

复制代码
void QuitSlaver(const std::vector<channel>& channels)
{
    for(const auto e:channels)
    {
        close(e._comdfd);
        waitpid(e._slaverid,nullptr,0);
    }
}

注意:关闭进程这里不能写成这样:

复制代码
  for(const auto &c : channels) close(c._cmdfd);
 
  for(const auto &c : channels) waitpid(c._slaverid, nullptr, 0);
相关推荐
w***488226 分钟前
Linux安装redis
linux·运维·redis
散峰而望2 小时前
C++数组(二)(算法竞赛)
开发语言·c++·算法·github
python百炼成钢2 小时前
28.嵌入式 Linux LED 驱动开发实验
linux·运维·驱动开发
利刃大大2 小时前
【动态规划:背包问题】完全平方数
c++·算法·动态规划·背包问题·完全背包
码途进化论3 小时前
用AI当嘴替、优雅终结技术争论!
经验分享
笑非不退3 小时前
C# c++ 实现程序开机自启动
开发语言·c++·c#
im_AMBER3 小时前
Leetcode 59 二分搜索
数据结构·笔记·学习·算法·leetcode
天殇凉4 小时前
AC自动机学习笔记
java·笔记·学习
AA陈超4 小时前
从0开始学习 **Lyra Starter Game** 项目
c++·笔记·学习·游戏·ue5·lyra
西风未眠4 小时前
高效编辑之vi/vim常用快捷键汇总
linux·编辑器·vim