【进程通信】利用管道创建进程池(结合代码)

文章目录

  • 什么叫进程池
    • 进程池的优点
  • 创建进程池
    • 代码实现:

什么叫进程池

我们知道,一个进程创建子进程通常是为了让这个子进程去为它完成某个任务。例如我们使用的指令,其实就是bash进程创建子进程让子进程去执行的。但是我们需要考虑这样一个问题:是不是遇到问题之后才创建子进程呢?

频繁的创建和销毁进程都是一项较大的开销,涉及到内存分配、上下文切换等操作。于是我们可以提前创建出一批进程,当有任务要做的时候就从这一批子进程中拿出一个空闲的去执行,一旦某个子进程把任务执行完之后也不立即销毁进程,而是等待下一个任务的来临。

我们把这些预先创建的一批子进程就叫做进程池。我们把进程池中的进程也称为工作进程

进程池的优点

  1. 通过复用已经创建的进程,减少创建和销毁进程的开销,提高了系统资源的利用与率和系统的性能。
  2. 动态调整进程池中工作进程的数量。可以让系统根据实际的负载和任务需求,动态的增加或者减少工作进程的数量,以适应不同的工作负载。提高了系统的工作的灵活性
  3. 简化编程。进程池提供了一种高级抽象,隐藏了底层进程管理的细节,使得并发进程更加简单和可靠。

创建进程池

现在我们尝试自己去实现一个进程池。
创建进程好很简单,如何管理这些进程呢?每创建一个进程我们都用一个结构体(或者类)维护,于是对工作进程的管理就变成了对结构体的管理,整个进程池从代码角度上来说就是一个结构体数组。

那我们如何将任务分配到工作进程呢?这个问题的本质其实是在问进程之间通信的方式。于是我们很容易的想到使用管道。父进程通过管道,将任务信息传递给子进程。

下面是使用进程池的一个简单模型:

在这里插入图片描述

代码实现:

Process.cpp文件


#include <iostream>
#include <cerrno>
#include <unistd.h>
#include <string>
#include <vector>
#include <sys/types.h>
#include <wait.h>
#include <sys/stat.h>
#include "Task.hpp"
using namespace std;// master
class Channel // 维护管道信息
{
public:Channel(int wfd, int subprocessid, string name): _wfd(wfd), _subprocessid(subprocessid), _name(name){}int GetWfd() { return _wfd; }int GetProcessId() { return _subprocessid; }string GetName() { return _name; }void CloseChannel(){ // 关闭信道的写端close(_wfd);}void Wait(){ // 关闭工作进程int status = 0;pid_t rid = waitpid(_subprocessid, NULL, 0);if (rid > 0){cout << "wait " << rid << " success" << endl;}}~Channel(){}private:int _wfd;          // 信道以写方式打开的文件描述符int _subprocessid; // 读端进程的pidstring _name;      // 信道的命名
};// 创建信道和子进程
void CreatChannelAndSub(int num, vector<Channel> &Channels, task_t task)
{ // task是一个回调函数for (int i = 0; i < num; i++){// 1.创建管道int pipefd[2];int n = pipe(pipefd);if (n < 0)exit(0);// 创建子进程pid_t pid = fork();if (pid == 0){// 关闭写端close(pipefd[1]);dup2(pipefd[0], 0); // 将管道的读端重定向到标准输入task();             // 子进程执行的任务close(pipefd[0]);exit(0);}// 父进程关闭读端,只用来输出任务close(pipefd[0]);string name = "Channel-" + to_string(i);// 将创建的信道存入输出型参数中Channels.push_back({pipefd[1], pid, name});}
}int NextChannel(int channelnum)
{static int next = 0;int channel = next;next = (next + 1) % channelnum;return channel;
}void SendTask(int taskcommand, Channel &channel)
{write(channel.GetWfd(), &taskcommand, sizeof(taskcommand));
}// 具体任务
void CtrlProcessOnce(vector<Channel> &Channels)
{// 1.选择一个任务int taskcommand = SelectTask();// 2.选择一个空信道int taskchannel = NextChannel(Channels.size());// 3.发送任务编号给信道SendTask(taskcommand, Channels[taskchannel]);cout << "taskcommand: " << taskcommand << " channel: " << Channels[taskchannel].GetName() << " sub process: " << Channels[taskchannel].GetProcessId() << endl;
}// 控制子进程执行任务
void CtrlProcess(vector<Channel> &Channels, int time = -1)
{ // time表示分配多少次任务给子进程去执行,默认是无限if (time == -1){ // 默认while (true){CtrlProcessOnce(Channels);sleep(1);}}else if (time > 0){while (time--){CtrlProcessOnce(Channels);sleep(1);}}
}void CleanUpChannel(vector<Channel> &channels)
{for (auto &it : channels){it.CloseChannel();}for (auto &it : channels){it.Wait();}
}int main(int argc, char *argv[])
{ // 参数列表,argv[1]表示创建的工作进程的数量,即内存池大小if (argc != 2){cerr << "Usage: " << argv[0] << " Processnum" << endl;return 1;}int num = stoi(argv[1]);// 加载任务LoadTask();vector<Channel> Channels; // 进程池// 创建信道和子进程CreatChannelAndSub(num, Channels, work1);// 通过Channel控制子进程CtrlProcess(Channels, 10);// 关闭子进程和信道的写端CleanUpChannel(Channels);return 0;
}

Task.hpp文件


#include <iostream>
#include <ctime>
#include <sys/stat.h>
#include <cstdlib>
#include <unistd.h>
#include <sys/types.h>
#define TASKNUM 3
using namespace std;typedef void (*task_t)(); // task_t函数指针类型void Print()
{ // 任务1cout << "Printf task" << endl;
}void DownLoad()
{ // 任务2cout << "DownLoad task" << endl;
}void Flush()
{ // 任务3cout << "Flush task" << endl;
}task_t tasks[TASKNUM]; // 用来存放函数指针void LoadTask()
{srand(time(nullptr));tasks[0] = Print;tasks[1] = DownLoad;tasks[2] = Flush;
}void ExcuteTask(int n)
{if (n < 0 || n > 2)return;tasks[n]();
}int SelectTask()
{int n = rand() % TASKNUM;return n;
}void work1()
{while (true){int command = 0;int n = read(0, &command, sizeof command); // 读取管道中的任务编号(int)if (n == sizeof(int)){ExcuteTask(command);}else if (n == 0){cout << "sub process: " << getpid() << " quit " << endl;break;}}
}

观察运行结果:
在这里插入图片描述

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

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

相关文章

【介绍下分布式系统】

&#x1f308;个人主页: 程序员不想敲代码啊 &#x1f3c6;CSDN优质创作者&#xff0c;CSDN实力新星&#xff0c;CSDN博客专家 &#x1f44d;点赞⭐评论⭐收藏 &#x1f91d;希望本文对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出指正&#xff0c;让我们共…

wegame启动游戏错误代码126,加载x3daudio1_7.dll失败的修复教程

在尝试通过WeGame平台启动某款游戏时&#xff0c;遇到了阻碍&#xff0c;系统反馈了一个特定的错误代码“错误代码126&#xff0c;加载x3daudio1_7.dll失败”。这个错误提示表示游戏无法加载x3daudio17.dll文件&#xff0c;导致游戏无法正常启动。经过一番研究和尝试&#xff0…

vue elementui el-table表格 点击单元格添加选中样式

注意&#xff1a; 1、点击某行单元格添加选中样式&#xff1b; 2、表格第一列数据单独添加样式&#xff0c;比如&#xff1a;加粗&#xff1b; 3、表格表头添加样式&#xff0c;比如&#xff1a;修改背景色&#xff1b; 先上代码&#xff08;效果图在文章末尾&#xff09;&…

python-pytorch 如何使用python库Netron查看模型结构(以pytorch官网模型为例)0.9.2

Netron查看模型结构 参照模型安装Netron写netron代码运行查看结果需要关注的地方 2024年4月27日14:32:30----0.9.2 参照模型 以pytorch官网的tutorial为观察对象&#xff0c;链接是https://pytorch.org/tutorials/intermediate/char_rnn_classification_tutorial.html 模型代…

Ansible自动化

Ansible自动化 自动化的需求&#xff1a; 1. 在什么样的场景下需要自动化&#xff1f; 批量化的工作&#xff1a; 装软件包、配置服务、升级、下发文件… 2. 为什么在自动化工具中选择ansible&#xff1f; 对比shell脚本&#xff1a; 相对于用shell的脚本来实现自动化&#x…

42.接雨水

接雨水是一个非常经典的题目了,我在二刷的时候,终于能独立做了,在记录一下灵神的横着计算的单调栈思想. 法一: 竖着计算 奇思妙想 让我们想想,接到的雨水到底是存储哪里了呢,其实他就是凹陷部分,而什么是凹陷呢,就是从左边看,从右边看都发现不了的地方. …

滑块验证码破解----Java使用opencv后端破解滑块验证

使用技术:Java SpringBootopenCV 在windows上首先需要下载opencv进行安装,先去官网:Releases - OpenCV 下载这个windows版本的安装包 下载后直接安装解压就行,然后需要,然后找到安装位置里的这个文件: 你下载的是什么版本的,这里的数字就是多少,比如我下载4.5.3版本那么这…

永磁同步电机SMO负载转矩观测matlab模型。

永磁同步电机SMO负载转矩观测matlab模型。 负载转矩的有效识别是提高伺服驱动系统抗负载扰动性能的关键之一。现在的传统结构的LTID滑模观测器存在频率抖动大&#xff0c;估计精度差的缺点&#xff0c;限制了其在高性能伺服系统中的应用。 本模型推导分析了传统LTID滑模观测器…

eclipse 如何创建python文件

一、准备 1.平台要求&#xff1a; 电脑除了要安装eclipse软件和Python语言包之外&#xff0c;还需要将Python集成到eclipse软件中&#xff0c;网上有很多的方法&#xff0c;这里就不细细介绍如何集成了。 在下面界面中可以看到自己已经安装了继承插件。具体方法见步骤2&…

AI新篇章:全面解读ChatGPT3.5与GPT4.0的革命性融合

MidTool&#xff08;kk.zlrxjh.top&#xff09;&#xff0c;一个集成了多种先进人工智能技术的助手&#xff0c;融合了ChatGPT3.5、GPT4.0、DALLE 3和Midjourney等多个智能服务&#xff0c;提供多功能体验。下面是对这些技术的简要概述&#xff1a; **ChatGPT3.5**&#xff1a;…

可视化智慧工厂

在科技迅猛发展的今天&#xff0c;制造业正迎来一场深刻的变革——智慧工厂的崛起。可视化智慧工厂作为其中的重要一环&#xff0c;以其直观、高效、智能的特点&#xff0c;正成为制造业转型升级的关键所在。 一、什么是可视化智慧工厂? 传统的制造业生产方式往往依赖于人工…

Typora配置PicGo图床,将图片文件上传到gitee厂库,获取图片链接显示在md文件中

Typora配置PicGo图床&#xff0c;将图片文件上传到gitee厂库&#xff0c;获取图片链接显示在md文件中 创建Gitee创库和配置私人令牌 名字、路径、描述自己随便添&#xff0c;但是必须开源&#xff0c;链接才能可以访问&#xff1a; 进入偏好设置 > 图像 > 选择PicGo-Cor…

找不到mfc140u.dll文件如何处理?这三种方法帮你快速修复mfc140u.dll

当你的电脑出现提示&#xff0c;显示找不到mfc140u.dll文件&#xff0c;从而无法继续执行代码&#xff0c;你需要知道如何应对这种情况。今天我们就来详细说明如何解决mfc140u.dll文件丢失的问题&#xff0c;并对该文件进行详细分析。这个文件是Microsoft Visual Studio的一个重…

Windows 安全中心:页面不可用 你的 IT 管理员已限制对此应用的某些区域的访问,并且你尝试访问的项目不可用。有关详细信息,请与 IT 支持人员联系。

问题 1&#xff1a;Windows 安全中心提示&#xff1a;【页面不可用 你的 IT 管理员已限制对此应用的某些区域的访问&#xff0c;并且你尝试访问的项目不可用。有关详细信息&#xff0c;请与 IT 支持人员联系。】 修复 Microsoft.SecHealthUI 方法 1&#xff1a;命令自动重装安…

Docker 部署与操作

一 国内&#xff1a; 中国电信天翼云 提供包括云主机在内的全方位云计算服务&#xff0c;侧重于安全合规和企业级服务。 利用电信的网络优势&#xff0c;提供稳定可靠的基础设施服务。 中国联通沃云 提供包括云主机在内的多项云计算服务&#xff0c;适合不同行业和场景。 …

【Spring Security系列】Spring Security整合JWT:构建安全的Web应用

前言 在企业级开发或者我们自己的课程设计中&#xff0c;确保用户数据的安全性和访问控制非常重要。而Spring Security和JWT是都两个强大的工具&#xff0c;它俩结合可以帮助我们实现这一目标。 Spring Security提供了全面的安全功能&#xff0c;而JWT则是一种用于身份验证的…

小程序为什么必须安装SSL证书?怎么挑选?——建议收藏

小程序使用SSL证书的原因主要包括&#xff1a; 1. 安全要求&#xff1a;微信小程序等平台强制要求使用HTTPS加密协议&#xff0c;这意味着必须部署SSL证书以确保所有网络请求的安全性。没有SSL证书&#xff0c;小程序无法正常上线使用。 2. 数据加密&#xff1a;SSL证书通过加密…

51单片机入门(一)

1. 51单片机的基础介绍 2. RAM和ROM的区别 总体而言&#xff0c;RAM和ROM在计算机系统中起着不同的角色&#xff0c;RAM用于临时存储运行时数据&#xff0c;而ROM用于存储永久性的固件和系统程序。 3. 为什么叫51单片机 因为51系列单片机都是使用Intel 8031指令系统的单片机…

linux网络编程启动!(开端)

网络设计模式 &#xff1a;就两种模型 b/s 模型 : 浏览器—>服务器 优点是&#xff1a;跨平台。开发成本低 缺点是&#xff1a;网络通信的时候必须要使用http/https协议 http协议 是个应用层协议 不能在磁盘缓存或者从磁盘加载大量数据 http 与https 多了一层加密 c/s模型 …

C# Solidworks二次开发:访问平面、曲面相关API详解

大家好&#xff0c;今天要介绍的是关于平面、曲面相关的API。 下面是相关的API: &#xff08;1&#xff09;第一个为ISurfacePlanarFeatureData&#xff0c;这个API的含义为允许访问平面表面特征&#xff0c;下面是官方的具体解释&#xff1a; 下面是官方使用的例子&#xff…