【Linux进程通信】使用匿名管道制作一个简单的进程池

进程池是什么呢?我们可以类比内存池的概念来理解进程池。

内存池

内存池是在真正使用内存之前,先申请分配一定数量的、大小相等(一般情况下)的内存块留作备用。当有新的内存需求时,就从内存池中分出一部分内存块,若内存块不够再继续申请新的内存。这样做的一个显著优点是,使得内存分配效率得到提升。

进程池

进程池是管理进程、资源进程组成的技术应用。进程池技术的应用至少由以下两部分组成:

管理进程:管理进程负责创建资源进程,把任务交给空闲的资源进程处理,回收已经处理完任务的资源进程。

资源进程:预先创建好的空闲进程,管理进程会把任务发送给空闲的资源进程处理。

管理进程要有效的管理资源进程,那么管理进程和资源进程之间必然需要交互,而他们就是通过管道进行信息交互的,还有其他的交互方式等等。

 制作一个简单的进程池的思路:我们为了实现两进程之间的通信(具有血缘关系的进程),父进程可以通过向子进程发送任务码来使子进程完成某个任务,传送信息的媒介就是匿名管道。

创建子进程并为每个子进程创建一个与父进程间进行通信的匿名管道。如下:

makefile 

ProcessPool:ProcessPool.cc
	g++ -o $@ $^ -std=c++11
.PHONY:clean
clean:
	rm -f ProcessPool

ProcessPool.hpp

#pragma once
#include <iostream>
#include <vector>
typedef void(*task)();//重命名函数指针类型
void task1()
{
    std::cout<<"更新野区"<<std::endl;
}
void task2()
{
    std::cout<<"回复生命值与法力值"<<std::endl;
}
void task3()
{
    std::cout<<"英雄升级"<<std::endl;
}
class Task
{
    public:
    task operator[](int pos)
    {
        if(pos>=0 && pos<=3)
        return tasks[pos];
    }
    private:
    task tasks[4]={nullptr,task1,task2,task3};//函数指针数组
};

ProcessPool.cc

#include "Task.hpp"
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <string>
#include <vector>
#include <cstdio>
#include <ctime>
#include <cassert>

#define NUM 2
#define processnum 5

class channel //创建描述管道写端和对应的子进程id的类
{
    public:
    channel(size_t cmdfd, pid_t slaverid, const std::string& slavername)
    :_cmdfd(cmdfd)//用来确定父进程向那个管道发送任务码
    ,_slaverid(slaverid)//子进程的pid
    ,_slavername(slavername)//子进程的名字
    {}
    public:
    size_t _cmdfd;
    pid_t _slaverid;
    std::string _slavername;
};

void Reader()
{
    Task t;
    while(true)
    {
        int childtaskcode;
        int n = read(0, &childtaskcode, sizeof(childtaskcode));
        if(0==n)//如果0==n则说明父进程的写端已关闭或父进程已终止
        break;
        else if(n==sizeof(int))
        t[childtaskcode]();
    }
}
void InitProcessPool(std::vector<channel>& channels)
{
    std::vector<int> uselesswfd;
    for(int i=0;i<processnum;i++)
    {
        int pipefd[NUM]={0};
        int n = pipe(pipefd);
        assert(!n);
        pid_t id = fork();
        //child
        if(0 == id)
        {
            std::cout<<"child process delete uselesswfd:";
            for(auto e:uselesswfd)
            {
                close(e);
                std::cout<< e <<" ";
            }
            std::cout<<std::endl;
            close(pipefd[1]);
            dup2(pipefd[0], 0);
            Reader();
            std::cout<<"child exit pid is:"<<getpid()<<std::endl;
            exit(0);
        }
        //parent
        uselesswfd.push_back(pipefd[1]);
        close(pipefd[0]);
        std::string name="process" + std::to_string(i);
        channels.push_back(channel(pipefd[1], id, name));//记录每一个管道的写端以及对应子进程pid
    }
}

void Menu()
{
    std::cout<<"******************************************"<<std::endl;
    std::cout<<"*******1.更新野区  2.回复生命值与法力值*****"<<std::endl;
    std::cout<<"*******3.英雄升级  0.退出             *****"<<std::endl;
}
void ControlChildProcess(const std::vector<channel>& channels) 
{
    int whichprocess=0;
    srand(time(nullptr));
    while(true)
    {
        sleep(1);
        std::cout<<std::endl;
        Menu();
        int taskcode;
        std::cout<<"Please select taskcode:";
        std::cin>>taskcode;

        if(taskcode<0 || taskcode>3)
        {
            std::cout<<"找不见对应的任务码!"<<std::endl;
            continue;
        }
        if(0==taskcode)
        break;

        whichprocess = rand()%channels.size();
        write(channels[whichprocess]._cmdfd, &taskcode, sizeof(taskcode));
    }
}

void Quitwaitchild(const std::vector<channel>& channels)
{
    for(auto& e : channels)
    close(e._cmdfd);
    for(auto& e : channels)
    waitpid(e._slaverid, nullptr,0);
}

int main()
{
    //描述并组织管道写端fd以及子进程pid
    std::vector<channel> channels;//用于存储管道和其对应的子进程信息
    
    //创建进程池,子进程阻塞等待管道内容
    InitProcessPool(channels);

    //父进程控制子进程,向子进程发送任务码让子进程执行相应的任务,并间接控制子进程终止
    ControlChildProcess(channels);

    //终止子进程并且父进程等待回收子进程
    Quitwaitchild(channels);

    return 0;
}

程序演示如下:

 

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

昇思25天学习打卡营第9天|FCN图像语义分割

FCN是Fully Convolutional Networks的简称&#xff0c;即全卷积网络。区别于全连接网络&#xff0c;全连接网络每层直接cell全部连接&#xff0c;全卷积网络即每层都进行卷积。全卷积网络不包含全连接层。 卷积说有点像缩放&#xff0c;具体的可以参考其他专门的介绍文章。 之…

WPF UI 3D 多轴 机械臂 stl 模型UI交互

鼠标交互&#xff08;没有强调场景的变换&#xff09; 鼠标命中测试&#xff08;HitTest 不推荐&#xff09; 平面对象加载 数据绑定&#xff08;数据与动作&#xff09; 环境配置与相关方法 模型准备&#xff1a;Blender/SolidWorks 模型导入 HelixToolkit更多案例…

Profibus转Modbus网关在智能化水处理系统优化改造的应用

一、背景 在现代水处理行业中&#xff0c;智能化系统的应用已经成为提高效率和降低成本的关键。特别是在水厂中&#xff0c;罐内压载水处理系统的自动化和监控对于保障水质安全至关重要。而在这一过程中需要将水泵、阀门、传感器等设备连接到中控系统上。 二、方案 在控制器与…

SpringBoot + 虚拟线程,性能炸裂!

一、什么是虚拟线程 虚拟线程是Java19开始增加的一个特性&#xff0c;和Golang的携程类似&#xff0c;一个其它语言早就提供的、且如此实用且好用的功能&#xff0c;作为一个Java开发者&#xff0c;早就已经望眼欲穿了。 二、虚拟线程和普通线程的区别 “虚拟”线程&#xf…

C语言+ MSSQL技术开发的 PACS系统源码:CT后处理技术之仿真内镜CTVE

C语言 MSSQL技术开发的 PACS系统源码&#xff1a;CT后处理技术之仿真内镜CTVE 仿真内窥镜VE VE是利用医学影像作为原始数据&#xff0c;融合图像处理、计算机图形学、科学计算可视化、虚拟现实技术&#xff0c;模拟传统光学内镜的一种技术。 又叫做腔内重建技术&#xff0c;是…

海参海胆数据集:探索现实世界水下图像增强的创新之旅(目标检测)

亲爱的读者们&#xff0c;您是否在寻找某个特定的数据集&#xff0c;用于研究或项目实践&#xff1f;欢迎您在评论区留言&#xff0c;或者通过公众号私信告诉我&#xff0c;您想要的数据集的类型主题。小编会竭尽全力为您寻找&#xff0c;并在找到后第一时间与您分享。 在当今…

Nginx(http配置、https配置)访问Spring Boot 项目

前文 记录一下在linux服务器下配置nginx中nginx.conf文件代理访问springboot项目 1. spring boot.yml配置 其他mysql,redis,mybatis等之类的配置就不一一列出了 # 自定义配置 为了等下验证读取的配置文件环境 appName: productserver:port: 8083 # 应用服务 WEB 访问端口s…

我做了个C++算法学习网站,从语法到算法再到数据结构,全方位为算法竞赛小伙伴护航

哈喽&#xff0c;各位小伙伴大家好&#xff0c;我是大李。 最近半个月&#xff0c;我做了个《C算法宝典》并更新了40多篇教程&#xff0c;目前还在更新中&#xff0c;内容从语法到算法和数据结构&#xff0c;全方位为算法竞赛小伙伴护航。 温馨提示&#xff1a;如果你或你的朋…

PDF一键转PPT文件!这2个AI工具值得推荐,办公必备!

PDF转换为PPT文件&#xff0c;是职场上非常常见的需求&#xff0c;过去想要把PDF文件转换为PPT&#xff0c;得借助各种文件转换工具&#xff0c;但在如今AI技术主导的大背景下&#xff0c;我们在选用工具时有了更多的选择&#xff0c;最明显的就是基于AI技术打造的AI格式转换工…

Android 如何通过代码实时设置EditTextView光标

背景&#xff1a;换肤框架下&#xff0c;QA进行深色浅色切换说输入框光标颜色没有改变&#xff0c;转UI结果UI说需要修改&#xff01;&#xff01;&#xff01;&#xff01;&#xff01; 本来有方法可以设置&#xff0c;但是 设置后未生效。重新进入该页面才生效&#xff01;&a…

C++——list类用法指南

一、list的介绍 1、list是可以在常数范围内在任意位置进行插入和删除的序列式容器&#xff0c;并且该容器可以前后双向迭代 2、list的底层是双向链表结构&#xff0c;双向链表中每个元素存储在互不相关的独立节点中&#xff0c;在节点中通过指针指向其前一个元素和后一个元素 …

在昇腾服务器上使用llama-factory对baichuan2-13b模型进行lora微调

什么是lora微调 LoRA 提出在预训练模型的参数矩阵上添加低秩分解矩阵来近似每层的参数更新&#xff0c;从而减少适配下游任务所需要训练的参数。 环境准备 这次使用到的微调框架是llama-factory。这个框架集成了对多种模型进行各种训练的代码&#xff0c;少量修改就可使用。 …

matplotlib mplot3d模块在Ubuntu 10.04中的问题与解决方法

在 Ubuntu 10.04 系统上使用 matplotlib 的 mplot3d 模块可能会遇到一些问题&#xff0c;主要涉及到库的安装和版本兼容性。Ubuntu 10.04 是一个比较老旧的版本&#xff0c;官方已经不再提供支持&#xff0c;这可能会导致一些库的版本较低&#xff0c;不支持最新的功能或修复。…

Flask 数据创建时出错

当我们在使用 Flask 创建数据时遇到错误&#xff0c;可能有多种原因&#xff0c;包括代码错误、数据库配置问题或依赖项错误。具体情况我会总结成一篇文章记录下&#xff0c;主要是归类总结一些常见的解决方法和调试步骤&#xff0c;帮助大家解决问题&#xff1a; 1、问题背景 …

自己分析的逆向案例八——中国新烟商盟登录密码加密

网址&#xff1a;会员登录 - 新商盟 登陆界面分析&#xff0c;找到登录接口&#xff0c;跟栈分析。 没有异步&#xff0c;也没有webpack,很简单的跟栈 打上断点&#xff0c;逐步网上找&#xff0c;找到$ajax老朋友 上面就有对密码加密的部分&#xff0c;是一个RSA加密。 b 被…

Git Flow 工作流学习要点

Git Flow 工作流学习要点 Git Flow — 流程图Git Flow — 操作指令优点&#xff1a;缺点&#xff1a;Git Flow 分支类型Git Flow 工作流程简述关于 feature 分支关于 Release 分支关于 hotfix 分支 总结 Git Flow — 流程图 图片来源&#xff1a;https://nvie.com/posts/a-succ…

三维家:SaaS的IT规模化降本之道|OceanBase 《DB大咖说》(十一)

OceanBase《DB大咖说》第 11 期&#xff0c;我们邀请到了三维家的技术总监庄建超&#xff0c;来分享他对数据库技术的理解&#xff0c;以及典型 SaaS 场景在数据库如何实现规模化降本的经验与体会。 庄建超&#xff0c;身为三维家的技术总监&#xff0c;独挑大梁&#xff0c;负…

分文件编译(简单学生系统)

定义学生基本信息 ①输出所有学生信息 ②删除某个学生后&#xff0c;输出所有学生信息 ③修改某个学生信息后&#xff0c;输出所有学生信息 ④查找某个学生的信息 main.c #include"k11*.h" int main(int argc, const char *argv[]) {struct student p[4]{{"…

注意!年龄越大,社交圈子越窄?其实这是老人的理性选择!数学家告诉你:何时该跳槽,何时该坚守!你必须知道的三个智慧:让你的人生更加精彩!

我们到底应该在什么情况下探索新事物&#xff0c;什么情况下专注于已有的东西呢&#xff1f;本质上来说&#xff0c;这个问题就是在询问&#xff0c;你究竟应该耗费精力去探索新的信息&#xff0c;还是专注从既有的信息中获取收获&#xff1f; 有人采访了临终的老人&#xff0c…

51单片机外部中断(按键识别)

欢迎入群共同学习交流 时间记录&#xff1a;2024/7/2 一、电路原理图 51单片机包含INT0、INT1两个外部中断接口 二、知识点介绍 1.中断寄存器位介绍 &#xff08;1&#xff09;TCON定时控制寄存器&#xff0c;位0&#xff08;IT0&#xff09;中断INT0请求信号选择位&#x…