Linux多进程(五) 进程池 C++实现

一、进程池的概念

1.1、什么是进程池

进程池是一种并发编程模式,用于管理和重用多个处理任务的进程。它通常用于需要频繁创建和销毁进程的情况,以避免因此产生的开销。

进程池的优点包括:

  1. 减少进程创建销毁的开销:避免频繁创建和销毁进程所带来的系统资源开销。
  2. 提高系统响应速度:由于进程已经初始化并且一直保持在内存中,可以立即分配执行任务,减少了任务等待时间。
  3. 控制资源使用:通过限制进程池中的进程数量,可以控制系统资源的使用情况,避免资源过度消耗。

1.2、管理进程

预先创建一些空闲进程,管理进程会把工作分发到空闲进程来处理,空闲进程处理结束后,通知管理进程。

管理进程需要将任务发给空闲的工作进程,这里就涉及到进程之间的通信,进程间的通信有以下三种方式,我们之前都做了详细的解释

管道:https://blog.csdn.net/weixin_43903639/article/details/138155634?spm=1001.2014.3001.5501

消息队列:https://blog.csdn.net/weixin_43903639/article/details/138155723?spm=1001.2014.3001.5501

共享内存:https://blog.csdn.net/weixin_43903639/article/details/138189200?spm=1001.2014.3001.5501

二、进程池模型

对于一个进程池,我们需要维护一个进程队列,如果进程在忙就等待,如果进程空闲,那么就给空闲进程发任务让进程去处理。

请添加图片描述

三、进程通信

我们这里采用了有名管道的方式。实际上使用匿名管道是一样的。为了方便管理,我们这里创建了一个Fifo的类,通过类将管道视为一个个的对象。

// 权限
#define Mode 0666
// 文件地址
#define Path "./default"class Fifo
{
public:Fifo(string path = Path, int mode = Mode) : _path(path), _mode(mode){int return_mkfifo_val = mkfifo(_path.c_str(), _mode);if (return_mkfifo_val < 0){cout << "mkfifo error:" << errno << " reason :" << strerror(errno) << endl;exit(1);}cout << "mkfifo success" << endl;}~Fifo(){int return_unlink_val = unlink(_path.c_str());if (return_unlink_val < 0){cout << "unlink error:" << errno << " reason :" << strerror(errno) << endl;}cout << "unlink namepipe success" << endl;}private:string _path;int _mode;
};

管道的默认权限是 0666,管道的默认文件地址是 ./default,这样管理的优势是便于管道的创建与销毁。

三、进程对象

我们将一个进程也视为一个对象,那么一个进程就需要以下的元素

  • fd0 : 管道,通过这个管道接收主进程的数据
  • fd1:管道,通过这个管道给主进程发数据
  • pid:子进程的pid
  • isbusy:此子进程是否在忙
class Process
{
public:Process(int fd0, int fd1, pid_t process_pid) : _fd0(fd0), _fd1(fd1), _process_pid(process_pid), _isbusy(false) {}~Process() {}// 获取父进程要写入的管道int get_fd0() { return _fd0; }// 获取子进程要写入的管道int get_fd1() { return _fd1; }// 获取子进程pidpid_t get_process_pid() { return _process_pid; }// 获取是否忙碌标志位bool get_isbusy() { return _isbusy; }// 修改标志为void set_isbusy(bool flag) { _isbusy = flag; }private:int _fd0;           // 父进程要写入的管道int _fd1;           // 父进程要读入的管道pid_t _process_pid; // 子进程pidbool _isbusy;       // 是否忙碌标志位
};

四、进程池

进程池就是同时管理管道和进程的。其中包含多个进程对象,每个进程对象又要包含两个管道。

  • vector<string> pipe0 主进程写入,子进程读的管道名
  • vector<string> pipe1 子进程写入,主进程读的管道名
  • vector<Fifo *> fifo0 主进程写入,子进程读的管道
  • vector<Fifo *> fifo1 子进程写入,主进程读的管道
  • vector<Process> _processpool 进程池管理的进程
  • int _processnum 进程池管理的进程数量
// 进程池
class ProcessPool
{
public:ProcessPool(int processnum) : _processnum(processnum) {}~ProcessPool(){for (int i = 0; i < _processnum; i++) {delete fifo0[i];delete fifo1[i];}// 要释放所有的子进程for (int i = 0; i<_processnum; i++) {// 通知子进程结束,通知失败的话直接杀死子进程if (kill(_processpool[i].get_process_pid(), SIGTERM) != 0) {// 杀死子进程kill(_processpool[i].get_process_pid(), SIGUSR1);}}}// 生成管道的名字void makePipeName(){pipe0.clear();pipe1.clear();for (int i = 0; i < _processnum; i++){string s0;s0 += "pipe0_" + to_string(i + 1);pipe0.push_back(s0);string s1;s1 += "pipe1_" + to_string(i + 1);pipe1.push_back(s1);}}// 创建进程池,接收一个参数的函数指针void CreateProcessPool(work_t work = worker){for (int i = 0; i < _processnum; i++){// 创建命名管道fifo0.push_back(new Fifo(pipe0[i]));fifo1.push_back(new Fifo(pipe1[i]));int id = fork();if (id == 0){// 子进程int fd0 = open(pipe0[i].c_str(), O_RDONLY);int fd1 = open(pipe1[i].c_str(), O_WRONLY);work(fd0, fd1);exit(0);}// 父进程打开管道,未发送任务int fd0 = open(pipe0[i].c_str(), O_WRONLY);int fd1 = open(pipe1[i].c_str(), O_RDONLY | O_NONBLOCK);// 设置为非阻塞模式fcntl(fd1, F_SETFL, O_NONBLOCK);_processpool.push_back({fd0, fd1, id});}}// 找到空闲进程返回进程在_processpool中的序号,没找到返回-1int getAChannal(){for (int i = 0; i < _processnum; i++){if (_processpool[i].get_isbusy() == false) {_processpool[i].set_isbusy(true);return i;}}return -1;}// 发送任务,任务就是数据void SendTask(char *data, int datasize){// 随机选中管道int luck_process = getAChannal();while (luck_process == -1) {// 看一下哪些进程是空闲的。每个进程结束后都会发送自己的pid。for (int i=0; i<_processnum; i++) {pid_t pid = 0;ssize_t bytes_read = read(_processpool[i].get_fd1(), &pid, sizeof(pid_t));if (bytes_read == -1) continue;// 哪个进程返回了数据,就认为Ta结束了。else {_processpool[i].set_isbusy(false);}}luck_process = getAChannal();}// 父进程向管道发送任务,发送任务就是向相应的管道写入数据write(_processpool[luck_process].get_fd0(), data, datasize);}static void worker(int fd0, int fd1){char buf[BUFSIZ];while (1){int read_return_value = read(fd0, buf, BUFSIZ);// 处理读取到的数据if (read_return_value > 0){cout << "my data is : " << buf << " my pid is : " << getpid() << endl;// 模拟处理读取到的数据sleep(1);}// 向消息队列传递自己的pid,表示已经完成任务pid_t pid = getpid();write(fd1, &pid, sizeof(pid_t));}}private:int _processnum;vector<string> pipe0; // 父进程写入,子进程读vector<string> pipe1; // 子进程写入,父进程读vector<Fifo *> fifo0;vector<Fifo *> fifo1;vector<Process> _processpool;
};

五、仿真

这里我们的工作函数是默认的工作函数,也就是打印传入的数据。

#include "ProcessPool.h"
#include <iostream>int main(int argc, char* argv[])
{ProcessPool* processpool = new ProcessPool(5);processpool->makePipeName();processpool->CreateProcessPool();char buf[3];for (int i=0;i<20;i++) {sprintf(buf,"%d",i+100);processpool->SendTask(buf,3);}delete processpool;return 0;
}

看一下仿真结果

image-20240425194002386

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

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

相关文章

vue与Spring boot数据交互例子【简单版】

文章目录 什么是Vue&#xff1f;快速体验Vueaxios是什么&#xff1f;向Springboot后端发送数据接收Springboot后端数据小结 什么是Vue&#xff1f; 官网解释&#xff1a;Vue 是一套用于构建用户界面的渐进式框架。与其它大型框架不同的是&#xff0c;Vue 被设计为可以自底向上…

(超全)python图像处理详细解析(3)

图像处理 23.保存视频每一帧图像24.把png图像转换成jpg并保存25.改变图像尺寸26.改变图像比例27.旋转图像28.亮度调整29.log对数调整30.判断图像对比度31.调整强度&#xff08;1&#xff09;强度调节&#xff08;2&#xff09;uint8转float 32.绘制直方图和均衡化33.彩色图片三…

FR-E840-0120-4-60 三菱变频器5.5KW型

FR-E840-0120-4-60 三菱变频器替换FR-E740-5.5K FR-E840用户手册,FR-E840-0120-4-60价格,FR-E840-5.5K价格,FR-E840-0120-4-60外部连接图,FR-E740-5.5K替换产品。 FR-E740-5.5K-CHT逐渐开始停产&#xff0c;现在用新型号FR-E840-0120-4-60替换。 FR-E840-0120-4-60参数说明&…

Grafana系列 | Grafana监控TDengine库数据 |Grafana自定义Dashboard

开始前可以去grafana官网看看dashboard文档 https://grafana.com/docs/grafana/latest/dashboards 本文主要是监控TDengine库数据 目录 一、TDengine介绍二、Grafana监控TDengine数据三、Grafana自定义Dashboard 监控TDengine库数据1、grafana 变量2、添加变量3、配置panel 一…

牛客NC406 最长山脉【中等 穷举,动态规划 C++/Java/Go/PHP】

题目 题目链接&#xff1a; https://www.nowcoder.com/practice/f4e974a50eda429fbf36515a4197b148 思路 参考答案C class Solution {public:/*** 代码中的类名、方法名、参数名已经指定&#xff0c;请勿修改&#xff0c;直接返回方法规定的值即可*** param nums int整型vect…

分类预测 | Matlab实现CNN-GRU-SAM-Attention卷积门控循环单元融合空间注意力机制的数据分类预测

分类预测 | Matlab实现CNN-GRU-SAM-Attention卷积门控循环单元融合空间注意力机制的数据分类预测 目录 分类预测 | Matlab实现CNN-GRU-SAM-Attention卷积门控循环单元融合空间注意力机制的数据分类预测分类效果基本描述程序设计参考资料 分类效果 基本描述 1.Matlab实现CNN-GRU…

linux 编译 opencv遇到问题

linux环境下完整编译opencv会需要很多依赖库&#xff0c;但是只需要编译部分模块的话可以这样做 opncv4.8版本是可以用的&#xff0c;只列举主要的参数&#xff0c;其他参数省略 cmake .. -DBUILD_LISTcore,highgui 这样就只会编译core、highgui以及它们依赖的so&#xff0c;…

云计算和边缘计算究竟有什么不同

在数据时代&#xff0c;无论是人的活动还是机器的运作都会产生各种各样海量的数据。在对数据梳理和筛选过程中&#xff0c;计算机的运算处理必不可少。为了减少本地计算机算力成本等限制&#xff0c;越来越多的企业选择了云计算和边缘计算。今天&#xff0c;德迅云安全就带您来…

20.Nacos集群搭建

模拟Nacos三个节点&#xff0c;同一个ip,启动三个不同的端口&#xff1a; 节点 nacos1, 端口&#xff1a;8845 节点 nacos2, 端口&#xff1a;8846 节点 nacos3, 端口&#xff1a;8847 1.搭建数据库&#xff0c;初始化数据库表结构 这里我们以单点的数据库为例 首先新建一…

无人机+巡飞弹:“柳叶刀”巡飞弹技术详解

“柳叶刀”巡飞弹技术是一种结合了无人机和巡飞弹的先进武器系统&#xff0c;由俄罗斯ZalaAero公司研制&#xff0c;首次公开亮相是在2019年的俄罗斯军队装备展上。该系统以其高度的灵活性和精确打击能力&#xff0c;在现代战场上扮演着重要角色。 系统组成&#xff1a;柳叶刀巡…

探索和构建 LLaMA 3 架构:深入探讨组件、编码和推理技术(四)分组多查询注意力

探索和构建 LLaMA 3 架构&#xff1a;深入探讨组件、编码和推理技术&#xff08;四&#xff09;分组多查询注意力 Grouped-query Attention&#xff0c;简称GQA 分组查询注意力&#xff08;Grouped-query Attention&#xff0c;简称GQA&#xff09;是多查询和多头注意力的插值…

Blender基础操作

1.移动物体&#xff1a; 选中一个物体&#xff0c;按G&#xff0c;之后可以任意移动 若再按X&#xff0c;则只沿X轴移动&#xff0c;同理可按Y与Z 2.旋转物体&#xff1a; 选中一个物体&#xff0c;按R&#xff0c;之后可以任意旋转 若再按X&#xff0c;则只绕X轴旋转&…

Python自学之路--003:PyCharm新建工程之后安装的Python第三方库找不到问题

目录 1、概述 2、问题原因 3、解决办法 3.1、.py文件通过.bat不能调用 3.2、通过调用之前PyCharm工程的解释器找到库 3.3、重新安装一遍或将库Copy到新工程的.venv里面 1、概述 通过PyCharm新建一个工程的时候发现&#xff0c;之前安装的python库没了&#xff0c;如下图。…

【Linux】:文件查看 stat、cat、more、less、head、tail、uniq、wc

&#x1f3a5; 屿小夏 &#xff1a; 个人主页 &#x1f525;个人专栏 &#xff1a; Linux深造日志 &#x1f304; 莫道桑榆晚&#xff0c;为霞尚满天&#xff01; 文章目录 &#x1f4d1;前言一、stat&#xff08;查看文件详细属性信息&#xff09;1.1 内容解析&#xff1a;1.2…

【linux高性能服务器编程】项目实战——仿QQ聊天程序源码剖析

hello &#xff01;大家好呀&#xff01; 欢迎大家来到我的Linux高性能服务器编程系列之项目实战——仿QQ聊天程序源码剖析&#xff0c;在这篇文章中&#xff0c;你将会学习到如何利用Linux网络编程技术来实现一个简单的聊天程序&#xff0c;并且我会给出源码进行剖析&#xff…

远程控制安卓手机:便捷、高效与安全的方法

在移动设备的领域里&#xff0c;远程控制安卓手机的能力也变得越来越重要。这种技术可以让我们在远程地点方便地操作手机&#xff0c;无论是处理紧急事务、帮助他人解决问题&#xff0c;还是仅仅为了享受科技带来的便利。本文将为你介绍2种便捷、高效且安全的方法&#xff0c;让…

【智能算法】向日葵优化算法(SFO)原理及实现

目录 1.背景2.算法原理2.1算法思想2.2算法过程 3.结果展示4.参考文献 1.背景 2019年&#xff0c;GF Gomes等人受到自然界向日葵运动行为启发&#xff0c;提出了向日葵优化算法&#xff08;Sunflower Optimization, SFO&#xff09;。 2.算法原理 2.1算法思想 SFO模拟向日葵行…

【服务器部署篇】Linux下Ansible安装和配置

作者介绍&#xff1a;本人笔名姑苏老陈&#xff0c;从事JAVA开发工作十多年了&#xff0c;带过刚毕业的实习生&#xff0c;也带过技术团队。最近有个朋友的表弟&#xff0c;马上要大学毕业了&#xff0c;想从事JAVA开发工作&#xff0c;但不知道从何处入手。于是&#xff0c;产…

vue3【详解】vue3 比 vue2 升级了哪些重要的功能?

改用 createApp 初始化实例 vue2 使用 new Vue() 初始化实例 vue3 使用 Vue.createApp() 初始化实例 新增 emits 选项 vue3 选项式API中新增了emits 选项&#xff0c;用于显示声明组件中的自定义事件&#xff0c;自定义事件的名称&#xff0c;需用 on 开头。 export default {…

如何在vue3+vite中优雅的使用iconify图标

前言 从Vue2迁移到Vue3&#xff0c;在使用上有着很大的差别。本文的话主要是针对图标的使用差别上进行分析&#xff0c;同时给出基于iconify图标库中unplugin-icons的用法。这里特殊说明一下&#xff1a;其实element-plus中用到的图标也是基于iconify图标库的&#xff0c;在我们…