【Linux】进程池
目录
进程池
进程池的概念:
手搓进程池:
1、创建信道和子进程
2、通过channel控制子进程
3、回收管道和子进程
进程池
进程池的概念:
定义一个池子,在里面放上固定数量的进程,有需求来了,就拿一个池中的进程来处理任务,等到处理完毕,进程并不关闭,直接将进程再放回进程池中继续等待任务;
如果有很多任务需要执行,池中的进程数量不够,任务就要等待之前的进程执行任务完毕归来,拿到空闲进程才能继续执行。也就是说,进池中进程的数量是固定的,那么同一时间最多有固定数量的进程在运行;这样不会增加操作系统的调度难度,还节省了开关进程的时间,也一定程度上能够实现并发效果。
看下图,父进程和子进程之间可以通过管道来交互;
如果管道中没有数据,则worker进程就阻塞等待;master向哪个管道写入就唤醒哪一个子进程来处理任务;

手搓进程池:
1、创建信道和子进程
我们用一个类来录父进程读写端的fd和子进程的id,用vector来存储;
- 先来创建一个管道(pipe)
- 管道创建成功后,再创建子进程(fork)
- 关闭不需要的fd
- 将信息存储到vector中
可以将上述代码封装到一个函数中,这样比较好看
#include <iostream>
#include <string>
#include <vector>
#include <unistd.h>
using namespace std;class channel
{
public:channel(int wfd, pid_t id, const string &name) : _wfd(wfd), childid(id), _name(name){}~channel(){}int getwfd() { return _wfd; }pid_t getid() { return childid; }string getname() { return _name; }private:int _wfd;pid_t childid;string _name;
};void work(int rfd)
{
}void create(vector<channel> &channels, int num)
{for (int i = 0; i < num; i++){int pipfd[2] = {0};int n = pipe(pipfd);pid_t id = fork();if (id == 0){// child --readclose(pipfd[1]);work(pipfd[0]);close(pipfd[0]);exit(0);}// father --writeclose(pipfd[0]);string name = "channel-" + to_string(i);channels.push_back(channel(pipfd[1], id, name));close(pipfd[1]);}}int main(int argc, char *argv[])
{if (argc != 2){cerr << "processnum???" << endl;return 1;}int num = stoi(argv[1]);// 1、创建子进程和信道vector<channel> channels;create(channels, num);for (auto channel : channels){cout << channel.getid() << " " << channel.getwfd() << " " << channel.getname() << endl;}}
运行结果:

2、通过channel控制子进程
信道建立好后,下面就是接收主进程给我们的任务就可以了,可是子进程如何接收和识别任务呢?
这里我们可以开一个hpp文件来模拟我们的任务:
.hpp文件是允许声明和实现写到一起的;
在这个文件中使用函数指针类型来初始化,并且有随机选择任务的函数,执行任务的函数;
#pragma once#include <iostream>
#include <ctime>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
using namespace std;#define NUM 3
typedef void (*task_t)();task_t tasks[NUM];// 创建任务
void Print()
{cout << "I am Print Task" << endl;
}
void Flush()
{cout << "I am Flush Task" << endl;
}
void Download()
{cout << "I am Download Task" << endl;
}// 初始化
void Loadtask()
{srand(time(nullptr) ^ getpid());tasks[0] = Print;tasks[1] = Download;tasks[2] = Flush;
}void Excutetask(int num)
{if (num < 0 || num > 2)return;tasks[num]();
}int selecttask()
{return rand()%NUM;
}
完成.hpp文件后,在我们的.cpp文件中添加对应的头文件;
- 随机选择一个任务
- 选择信道和进程
- 发送任务----父进程完成write操作,子进程完成read操作


运行结果:

3、回收管道和子进程
- 关闭所有w端
- wait,回收子进程

完整代码:
#include <iostream>
#include <string>
#include <vector>
#include <unistd.h>
#include "test.hpp"
#include <sys/types.h>
#include <sys/wait.h>
using namespace std;class channel
{
public:channel(int wfd, pid_t id,const string &name) : _wfd(wfd), childid(id), _name(name){}~channel(){}int getwfd() { return _wfd; }pid_t getid() { return childid; }string getname() { return _name; }void closechannel(){close(_wfd);}void wait(){pid_t rid =waitpid(childid,nullptr,0);if(rid>0){cout<<"wair sucess"<<endl;}}private:int _wfd;pid_t childid;string _name;
};void work(int rfd)
{while (true){int command = 0;int n = read(rfd, &command, sizeof(command));if (n == sizeof(int)){Excutetask(command);}}
}void create(vector<channel> &channels, int num)
{for (int i = 0; i < num; i++){int pipfd[2] = {0};int n = pipe(pipfd);pid_t id = fork();if (id == 0){// child --readclose(pipfd[1]);work(pipfd[0]);close(pipfd[0]);exit(0);}// father --writeclose(pipfd[0]);string name = "channel-";name += to_string(i);channels.push_back(channel(pipfd[1], id, name));}
}int selectchannel(int num)
{static int index = 0;int next = index;index++;index %=num;return next;
}
void send(int selectnum, int channel_index, vector<channel> &channels)
{write(channels[channel_index].getwfd(), &selectnum, sizeof(selectnum));
}void controlonce(vector<channel> &channels)
{// 2.1、选一个任务int selectnum = selecttask();// 2.2、选一个信道和进程int channel_index = selectchannel(channels.size());// 2.3、发送---父进程w,子进程rsend(selectnum, channel_index, channels);cout << "信息发送成功" << endl;
}
void control(vector<channel> &channels, int times = -1)
{if (times > 0){while(times--){controlonce(channels);}}else{while (true){controlonce(channels);}}
}void clean(vector<channel> &channels)
{for(auto channel:channels){channel.closechannel();}for(auto channel:channels){channel.wait();}
}int main(int argc, char *argv[])
{if (argc != 2){cerr << "processnum???" << endl;return 1;}int num = stoi(argv[1]);Loadtask();// 1、创建子进程和信道vector<channel> channels;create(channels, num);// for (auto channel : channels)// {// cout << channel.getid() << " " << channel.getwfd() << " " << channel.getname() << endl;// }// 2、通过channel控制子进程control(channels, 10);//3、回收管道和子进程clean(channels);
}
以上就是进程池的知识点,希望有所帮助!!!
相关文章:
【Linux】进程池
目录 进程池 进程池的概念: 手搓进程池: 1、创建信道和子进程 2、通过channel控制子进程 3、回收管道和子进程 进程池 进程池的概念: 定义一个池子,在里面放上固定数量的进程,有需求来了,就拿一个池中…...
实验23:DA呼吸灯实验
电路硬件: 实现功能: 代码: public.h #ifndef _public_H #define _public_H#include "reg52.h" //#include "key.h"typedef unsigned int u16; typedef unsigned char u8;void delay_10us(u16 n); void delay_ms(u16 ms);#endif public.c #include …...
安科瑞智慧能源管理系统EMS3.0在浙江某能源集团有限公司的应用
安科瑞戴婷 Acrel-Fanny 一、项目背景 浙江某能源集团有限公司位于浙江省宁波前湾新区,主营业务范围包括了储能技术服务,光伏风力发电技术服务,充电桩技术服务,新能源项目的施工以及为企业提供配电房运维服务。 随着新能源的兴…...
线性代数学习
1.标量由只有一个元素的张量表示 import torchx torch.tensor([3,0]) y torch.tensor([2,0])x y, x * y, x / y, x**y 2.可以将向量视为标量值组成的列表 x torch.arange(4) x 3.通过张量的索引访问任一元素 x[3] 4.访问张量长度 len(x) 5.只有一个轴的张量,…...
FineReport 数据显示格式
原始 修改 选择「单元格元素>格式」,选择「日期型」,改成 「yyyy 年 MM 月 dd 日」,如下图所示: 注:若列表中没有 yyyy 年 MM 月 dd 日 格式,可手动输入 选择运货费数据列单元格,选择「单元…...
leetcode.204.计数质数
#中等#枚举 给定整数 n ,返回 所有小于非负整数 n 的质数的数量 。 埃氏筛 枚举没有考虑到数与数的关联性,因此难以再继续优化时间复杂度。接下来我们介绍一个常见的算法,该算法由希腊数学家厄拉多塞(Eratosthenes)提…...
Mysql环境安装
1,下载压缩包 下载压缩包解压 2,配置环境变量 i,高级系统设置-->环境变量-->系统变量-->path-->添加mysql的bin目录路径 ii,新建my.ini文件 basedir:MYSQL的路径 datadir:这个data路径不用手动创建&am…...
请问平面仓系统的盘点如何做?
盘点流程 一、盘点任务生成 手动发起:仓库管理人员可以根据实际需要,在系统中手动发起库存盘点任务。例如,定期进行全盘、抽盘或者在发现库存数据异常时发起盘点。自动触发:系统可以设置自动触发盘点的条件,如每隔一…...
STM32笔记(1)GPIO之点亮LED
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 总结 第一步:先看原理图。PB0输出高电平是,LED1点亮。 初始化完成了两项工作: (1)从时钟上启动所用GPIO所在的总线;…...
自动化工具
自动化工具确保测试准确性的关键在于采取一系列综合性措施,包括但不限于以下几点: 环境一致性:确保测试环境与生产环境尽可能相似,减少环境差异导致的结果不准确。可以通过容器技术(如Docker和Kubernetes)确…...
CTFHUB技能树之HTTP协议——响应包源代码
开启靶场,打开链接: 是个贪吃蛇小游戏,看不出来有什么特别的地方 用burp抓包看看情况: 嗯?点击“开始”没有抓取到报文,先看看网页源代码是什么情况 居然直接给出flag了,不知道这题的意义何在 …...
Java会话技术,拦截器,过滤器,登录校验
目录 1.会话: 2.会话跟踪: 3.会话跟踪方案: 客户端会话跟踪技术:Cookie 服务端会话跟踪技术:Session JWT令牌技术(https://jwt.io/) 定义: 优点: 缺点: 组成: …...
Spring Security 如何进行权限验证
阅读本文之前,请投票支持这款 全新设计的脚手架 ,让 Java 再次伟大! FilterSecurityInterceptor FilterSecurityInterceptor 是负责权限验证的过滤器。一般来说,权限验证是一系列业务逻辑处理完成以后,最后需要解决的…...
计算机砖头书的学习建议
纸上得来终觉浅,绝知此事要躬行,技术来源于实践,光看不练意义不大,过阵子全忘记,并且没有实践来深化理论认知。 “砖头书”通常指的是那些厚重、内容详实且权威的书籍,对于计算机科学领域而言,…...
我与C语言二周目邂逅vlog——7.预处理
C语言预处理详解 C语言预处理是编译过程中的重要组成部分,用于对源代码进行文本替换和修改。预处理发生在编译的前期,通过特定的指令来控制代码的编译行为,最终生成可以交给编译器进行进一步处理的代码。预处理的目的是简化代码编写…...
Python无监督学习中的聚类:K均值与层次聚类实现详解
📘 Python无监督学习中的聚类:K均值与层次聚类实现详解 无监督学习是一类强大的算法,能够在没有标签的数据集中发现结构与模式。聚类作为无监督学习的重要组成部分,在各类数据分析任务中广泛应用。本文将深入讲解聚类算法中的两种…...
C++ 中 new 和 delete 详解,以及与 C 中 malloc 和 free 的区别
1. C 中 new 和 delete 的基本用法 在 C 中,new 和 delete 是用来动态分配和释放内存的关键字,它们是面向对象的替代方式,提供了比 C 语言更优雅的内存管理工具。 1.1 new 的使用 new 用于从堆中分配内存,并且自动调用对象的构造…...
YOLOv11来了 | 自定义目标检测
概述 YOLO11 在 2024 年 9 月 27 日的 YOLO Vision 2024 活动中宣布:https://www.youtube.com/watch?vrfI5vOo3-_A。 YOLO11 是 Ultralytics YOLO 系列的最新版本,结合了尖端的准确性、速度和效率,用于目标检测、分割、分类、定向边界框和…...
Vue3 集成Monaco Editor编辑器
Vue3 集成Monaco Editor编辑器 1. 安装依赖2. 使用3. 效果 Monaco Editor (官方链接 https://microsoft.github.io/monaco-editor/)是一个由微软开发的功能强大的在线代码编辑器,被广泛应用于各种 Web 开发场景中。以下是对 Monaco Editor 的…...
一文详解Mysql索引
背景 索引是存储引擎用于快速找到一条记录的数据结构。索引对良好的性能非常关键。尤其是当表中的数据量越来越大时,索引对性能的影响愈发重要。接下来,就来详细探索一下索引。 索引是什么 索引(Index)是帮助数据库高效获取数据的…...
设计模式和设计原则回顾
设计模式和设计原则回顾 23种设计模式是设计原则的完美体现,设计原则设计原则是设计模式的理论基石, 设计模式 在经典的设计模式分类中(如《设计模式:可复用面向对象软件的基础》一书中),总共有23种设计模式,分为三大类: 一、创建型模式(5种) 1. 单例模式(Sing…...
PHP和Node.js哪个更爽?
先说结论,rust完胜。 php:laravel,swoole,webman,最开始在苏宁的时候写了几年php,当时觉得php真的是世界上最好的语言,因为当初活在舒适圈里,不愿意跳出来,就好比当初活在…...
Debian系统简介
目录 Debian系统介绍 Debian版本介绍 Debian软件源介绍 软件包管理工具dpkg dpkg核心指令详解 安装软件包 卸载软件包 查询软件包状态 验证软件包完整性 手动处理依赖关系 dpkg vs apt Debian系统介绍 Debian 和 Ubuntu 都是基于 Debian内核 的 Linux 发行版ÿ…...
Cesium1.95中高性能加载1500个点
一、基本方式: 图标使用.png比.svg性能要好 <template><div id"cesiumContainer"></div><div class"toolbar"><button id"resetButton">重新生成点</button><span id"countDisplay&qu…...
uni-app学习笔记二十二---使用vite.config.js全局导入常用依赖
在前面的练习中,每个页面需要使用ref,onShow等生命周期钩子函数时都需要像下面这样导入 import {onMounted, ref} from "vue" 如果不想每个页面都导入,需要使用node.js命令npm安装unplugin-auto-import npm install unplugin-au…...
Nuxt.js 中的路由配置详解
Nuxt.js 通过其内置的路由系统简化了应用的路由配置,使得开发者可以轻松地管理页面导航和 URL 结构。路由配置主要涉及页面组件的组织、动态路由的设置以及路由元信息的配置。 自动路由生成 Nuxt.js 会根据 pages 目录下的文件结构自动生成路由配置。每个文件都会对…...
数据链路层的主要功能是什么
数据链路层(OSI模型第2层)的核心功能是在相邻网络节点(如交换机、主机)间提供可靠的数据帧传输服务,主要职责包括: 🔑 核心功能详解: 帧封装与解封装 封装: 将网络层下发…...
论文浅尝 | 基于判别指令微调生成式大语言模型的知识图谱补全方法(ISWC2024)
笔记整理:刘治强,浙江大学硕士生,研究方向为知识图谱表示学习,大语言模型 论文链接:http://arxiv.org/abs/2407.16127 发表会议:ISWC 2024 1. 动机 传统的知识图谱补全(KGC)模型通过…...
Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决
Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决 问题背景 在一个基于 Spring Cloud Gateway WebFlux 构建的微服务项目中,新增了一个本地验证码接口 /code,使用函数式路由(RouterFunction)和 Hutool 的 Circle…...
C++.OpenGL (14/64)多光源(Multiple Lights)
多光源(Multiple Lights) 多光源渲染技术概览 #mermaid-svg-3L5e5gGn76TNh7Lq {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-3L5e5gGn76TNh7Lq .error-icon{fill:#552222;}#mermaid-svg-3L5e5gGn76TNh7Lq .erro…...
