Linux--进程间的通信--进程池

进程间的通信–匿名管道

进程池的概念

进程池是一种将多个进程组织起来以执行特定任务的机制它由多个预先创建好的资源进程和一个管理进程组成。这些资源进程被管理进程负责分配和调度,用于处理任务

当有新的任务提交时,管理进程会从进程池中取出一个资源进程,将任务分发给它来处理。任务完成后,资源进程并不会被关闭,而是被放回进程池中,等待处理其他的任务。这样可以避免频繁地创建和销毁进程,节省了时间和资源。

进程池的主要优势包括减少操作系统的调度难度,节省创建和销毁进程的时间,并在一定程度上实现并发效果。通过有效地管理资源进程和任务分配,进程池可以提高系统的整体性能和效率。

下面我们来模拟实现进程池,来加深对进程池的理解。

模拟场景

通过主程序的创建,当做管理进程;然后再创建几个子进程作为资源进程,在主函数模拟n个任务来临时,轮盘调用可用的资源进程。

代码

task.hpp:这是一个任务头文件,包含了有关任务的模拟,任务的处理,任务的派发的任务有关函数。

#pragma once

#include<iostream>
#include<unistd.h>
using namespace std;

typedef void(*work_t)(int);
typedef void(*task_t)(int,pid_t);

void PrintLog(int fd,pid_t pid)
{
    cout << "sub process: " << pid << ", fd: " << fd<< ", task is : printf log task" << endl;
}
void ReloadConf(int fd,pid_t pid)
{
    cout << "sub process: " << pid << ", fd: " << fd<< ", task is : reload conf task" << endl;
}
void ConnectMysql(int fd,pid_t pid)
{
    cout << "sub process: "<< pid <<", fd: "<<fd<< ",task is: connact mysql task"<<endl;
}

task_t task[3]={PrintLog,ReloadConf,ConnectMysql};

uint32_t NextTask()
{
    return rand()%3;
}
void worker(int fd)
{
    while(true)
    {
        uint32_t commond_code=0;
        ssize_t n=read(0,&commond_code,sizeof(commond_code));
        if(n==sizeof(commond_code))
        {
            if(commond_code >=3)continue;
            task[commond_code](fd,getpid());
        }
        else if(n==0)
        {
            cout<<"get sub_process:"<<getpid()<<" quit now:"<<endl;
            break;
        }
        cout<<"I am worker : "<<getpid()<<endl;
        sleep(1);
    }
}

processpool.cpp: 这里面包含了进程池(创建资源进程、发送任务码、回收资源进程、资源进程的管理)、进程池的控制(进程通道的选择、任务的选择、任务的选择)、进程间的通道(包含父进程的文件标识符、子进程的进程ID、通道的名称)以及主函数;

#include<iostream>
#include<string>
#include<cstdlib>
#include<unistd.h>
#include<vector>
#include<ctime>
#include<sys/wait.h>
#include"task.hpp"

using namespace std;


enum
{
    UsageError=1,
    ArgError,
    PipeError
};

void Usage(const std::string &proc)
{
    cout<<"Usage: "<<proc<<"subprocess-num"<< endl;
}

class channel
{
public:
    channel(int wfd,pid_t sub_id,const std::string& name)
    :_wfd(wfd),
    _sub_process_id(sub_id),
    _name(name)
    {}

    void PrintDebug()
    {
        cout<<"_wfd:"<<_wfd<<" ";
        cout<<"_sub_process_id:"<<_sub_process_id<<" ";
        cout<<"_name:"<<_name<<" ";
        cout<<endl;
    }
    string name(){return _name;}
    int wfd(){ return _wfd;}
    pid_t pid() { return _sub_process_id;}
    void Close() { close(_wfd); }
    ~channel()
    {}
private:
    int _wfd;
    pid_t _sub_process_id;
    string _name;
};

class ProcessPool
{
public:
    //构造函数初始化
    ProcessPool(int sub_process_num)
    :_sub_process_num(sub_process_num)
    {}

    int CreateProcess(work_t work)
    {
        vector<int> fds;
        for(int number=0;number<_sub_process_num;number++)
        {
            int pipefd[2]{0};
            int n=pipe(pipefd);
            if(n<0)
            {
                return PipeError;
            }
            pid_t id=fork();
            if(id==0)
            {
                if(!fds.empty())
                {
                    cout<<"close w fd:";
                    for(auto fd:fds)
                    {
                        close(fd);
                        cout<<fd<<" ";
                    }
                    cout<<endl;
                }
                //child
                close(pipefd[1]);
                //执行任务  
                dup2(pipefd[0],0);
                work(pipefd[0]);
                exit(0);
            }
            string cname="channel-"+ to_string(number);

            close(pipefd[0]);
            //保存对应的子进程通道信息
            _channels.push_back(channel(pipefd[1],id,cname));
            //将父进程的fd进行保存
            fds.push_back(pipefd[1]);
        }

        return 0;
    }
    int NextChannel()
    {
        static int next =0;
        int c=next;
        next++;
        next%=_channels.size();
        return c;
    }
    void SendTaskCode(int index,uint32_t code)
    {
        cout<<"send code: "<<code<<" to "<<_channels[index].name()<<" sub process id: "<<_channels[index].pid()<<endl;
        write(_channels[index].wfd(),&code,sizeof(code));
    }
    void KillAll()
    {
        for(auto& C : _channels)
        {
            C.Close();
            pid_t pid=C.pid();//获取对应子进程id
            //waitpid()成功返回子进程的ID,失败返回-1;
            pid_t rid=waitpid(pid,nullptr,0);
            if(rid==pid)
            {
                cout<<"wait sub_process: "<<pid<<"sucess..."<<endl;
            }
            cout<<C.name()<<" close done"<<" sub process quit now"<<C.pid()<<endl;
        }
    }
    void Debug()
    {
        for(auto& channel: _channels)
        {
            channel.PrintDebug();
        }
    }
    ~ProcessPool()
    {}
private:
    int _sub_process_num;
    vector<channel> _channels;
};

void CtrlProcessPool(ProcessPool* processpool_ptr,int cnt)
{
    while(cnt)
    {
        //选择一个进程和通道
        int channel=processpool_ptr->NextChannel();

        //选择一个任务
        uint32_t code=NextTask();

        //发送任务
        processpool_ptr->SendTaskCode(channel,code);
        
        sleep(1);
        cnt--;
    }
}

//,/processpool 5
int main(int argc,char* argv[])
{
    if(argc!=2)
    {
       Usage(argv[0]);
        return UsageError;
    }
    int sub_process_num=std::stoi(argv[1]);
    if(sub_process_num <=0) return ArgError;
    
    srand((uint64_t)time(nullptr));
    //创建通信和子进程
    ProcessPool *processpool_ptr=new ProcessPool(sub_process_num);
    processpool_ptr->CreateProcess(worker);
    processpool_ptr->Debug();

    //控制子进程
    CtrlProcessPool(processpool_ptr,sub_process_num);
    cout<<"task run done"<<endl;
    
    //sleep(100);

    //回收子进程
    processpool_ptr->KillAll();

    delete processpool_ptr;
    return 0;
}



讲解

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

如果匿名管道有多个写端,情况会比较复杂。匿名管道的特性决定了它只能实现一对一的通信,即一个写端对应一个读端。如果多个写端同时写入数据,可能会导致以下问题:

  • 1.写入顺序混乱:由于多个写端并发写入,写入的顺序可能会混乱,导致数据的顺序不可预测。
  • 2.写入内容被覆盖:多个写端同时写入时,如果没有采取合适的同步机制,可能会发生数据覆盖的情况,即后面的写入会覆盖前面的写入结果。
  • 3.数据丢失:如果某个写端写入速度快于其他写端,读端可能无法及时消费所有写入的数据,导致数据丢失。

为了避免这些问题,通常需要在使用匿名管道时进行适当的同步操作,例如使用互斥锁、条件变量等机制来保证多个写端之间的互斥访问和顺序执行。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

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

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

相关文章

2024北京门窗展|2024北京门窗展会|2024北京门窗展览会

CWE中国&#xff08;北京&#xff09;国际系统门窗及幕墙博览会 CWE China&#xff08;Beijing&#xff09;International System Doors Windows and Curtain Walls Expo 2024年8月29-31日 北京&#xff0c;中国国际展览中心顺义馆 展会概况&#xff1a; 2024年CWE中国&…

【Unity】ScriptableObject 在游戏中的使用实例

ScriptableObject 在游戏中的使用实例 ScriptableObject 使用指南Unity 存储游戏数据的几种方法Unity ScriptableObject实例创建一个物品管理的ScriptableObject创建一个管理所有 ScriptableObject 的数据库&#xff08;ItemDBSO&#xff09; ScriptableObject 使用指南 Scrip…

回溯算法练习day.2

216.组合总和III 链接&#xff1a;. - 力扣&#xff08;LeetCode&#xff09; 题目描述&#xff1a; 找出所有相加之和为 n 的 k 个数的组合&#xff0c;且满足下列条件&#xff1a; 只使用数字1到9每个数字 最多使用一次 返回 所有可能的有效组合的列表 。该列表不能包含相…

基于STM32的RFID智能门锁系统

本文针对RFID技术&#xff0c;着重研究了基于单片机的智能门锁系统设计。首先&#xff0c;通过链接4*4按键模块与主控STM32&#xff0c;实现了多种模式&#xff0c;包括刷卡开锁、卡号权限管理、密码开锁、修改密码、显示实时时间等功能。其次&#xff0c;采用RC522模块与主控S…

【C语言基础】:预处理详解(二)

文章目录 一、宏和函数的对比二、#和##运算符2.1 #运算符2.2 ##运算符 三、#undef四、命令行定义五、条件编译六、头文件的包含1. 头文件包含的方式2. 嵌套文件包含 上期回顾&#xff1a; 【C语言基础】&#xff1a;预处理详解(一) 一、宏和函数的对比 宏通常被应有于执行简单…

Vue3---基础10(路由)

写一个最基本的路由导航 下载、创建、使用路由 下载路由 npm i vue-router 创建路由 先在 src 内去创建一个 router 文件夹 在文件夹内创建一个 index 文件 index.ts 内代码 // 创建一个路由器&#xff0c;并暴露出去 // 引入createRouter import { createRouter, createWeb…

CSS使用自己的字体

在项目的根目录下的static文件夹中放置字体文件。在项目中使用这个字体&#xff0c;需要2个步骤。 一. 你需要在全局样式文件中引入它。 假设你的全局样式文件是App.vue或者App.vue中引入的App.scss文件&#xff0c;你可以像这样引入字体文件&#xff1a; font-face {font-fa…

深度学习体系结构——CNN, RNN, GAN, Transformers, Encoder-Decoder Architectures算法原理与应用

1. 卷积神经网络 卷积神经网络&#xff08;CNN&#xff09;是一种特别适用于处理具有网格结构的数据&#xff0c;如图像和视频的人工神经网络。可以将其视作一个由多层过滤器构成的系统&#xff0c;这些过滤器能够处理图像并从中提取出有助于进行预测的有意义特征。 设想你手…

MySQL中的存储过程详解(上篇)

使用语言 MySQL 使用工具 Navicat Premium 16 代码能力快速提升小方法&#xff0c;看完代码自己敲一遍&#xff0c;十分有用 拖动表名到查询文件中就可以直接把名字拉进来中括号&#xff0c;就代表可写可不写 目录 1.认识存储过程 1.1 存储过程的作用 1.2 存储过程简介…

C#基础|数据类型、变量

哈喽&#xff0c;你好啊&#xff0c;我是雷工&#xff01; 01 数据类型 数据类型是为了方便存储数据的&#xff0c;为了将数据按照不同的分类存储&#xff0c;所以引入数据类型。这个在PLC中已经很熟悉了。 数据类型的作用&#xff1a;就是为了更好地管理内存&#xff0c;为…

顺序表 (头删 尾删 清空)

//头删 | 1 #include "head.h" | 1 #ifndef ww87 void head_del(p lp) | 2 int main(int argc, const char *argv[]) …

[C++][算法基础]求最小生成树(Kruskal)

给定一个 n 个点 m 条边的无向图&#xff0c;图中可能存在重边和自环&#xff0c;边权可能为负数。 求最小生成树的树边权重之和&#xff0c;如果最小生成树不存在则输出 impossible。 给定一张边带权的无向图 G(V,E)&#xff0c;其中 V 表示图中点的集合&#xff0c;E 表示图…

民航电子数据库:[E14024]事务内变更操作次数超过最大许可值10000,可通过系统参数max_trans_modify适当调整限制

目录 一、场景二、异常情况三、原因四、排查五、解决 一、场景 1、对接民航电子数据 2、执行delete语句时报错 二、异常情况 三、原因 通过报错信息就可以看出&#xff0c;是系统参数max_trans_modify配置导致 当删除的数据量 > max_trans_modify时&#xff0c;删除就会…

Visual studio项目默认“Header Files”、“Source Files”等过滤器消失后展开的方法。

使用Visual Studio进行项目开发创建默认工程的解决方案资源管理器里查看项目文件&#xff0c;所有的文件是按照其所属的类型自动归类&#xff0c;例如&#xff1a;.h头文件自动划归到Header Files文件夹&#xff0c;.cpp文件自动划归到Source Files文件夹下&#xff0c;如下图所…

关于AG32 MCU的一些奇思妙想

1、AG32VF103的网口是100M还是10M&#xff1f; RE: 都是100M的。 2、用FPGA能不能再仿出一个网口&#xff1f;有些产品用到两个网口。 理论上可以&#xff0c;但是要考虑&#xff0c;一个是cpld实现难度&#xff0c;一个是需要的逻辑单元。因为mac逻辑多&#xff0c;内置的2KL…

Python Flask Web 框架-API接口开发_4

一、1、安装 Falsk 当前用户安装 pip3 install --user Flask 确认安装成功&#xff1a; 进入python交互模式看下Flask的介绍和版本&#xff1a; $ python3>>> import flask >>> print(flask.__doc__)flask~~~~~A microframework based on Werkzeug. Its …

快速掌握Spring监控(Spring Boot admin)

监控 监控可视化监控平台Admin底层逻辑info 自定义端点 监控 监控的作用&#xff1a; 监控服务状态是否宕机监控服务运行指标&#xff08;内存&#xff0c;虚拟机&#xff0c;线程&#xff0c;请求等&#xff09;监控日志管理服务&#xff08;服务下线&#xff09; 监控的实…

linux进阶篇:使用Apache搭建文件服务器目录

Linux服务搭建篇&#xff1a;使用Apache搭建文件服务器目录 一、关于文件服务器 ​ 在一个项目中&#xff0c;如果想把公共软件或者资料共享给项目组成员&#xff0c;可以搭建一个简易的文件服务器来实现&#xff0c;只要是在局域网内的成员都可以通过浏览器或者wget命令来下…

书生·浦语大模型全链路开源体系-第5课

书生浦语大模型全链路开源体系-第5课 书生浦语大模型全链路开源体系-第5课相关资源LMDeploy基础配置LMDeploy运行环境下载internlm2-chat-1_8b模型使用Transformer来直接运行InternLM2-Chat-1.8B模型使用LMDeploy以命令行方式与InternLM2-Chat-1.8B模型对话设置KV Cache最大占用…

wps使用Latex编辑公式没有Latex formula

wps使用Latex编辑公式没有Latex formula 1. 下载CTEX2. 下载LaTeXEE3. 配置Miktex4. 配置latexee5. 用管理员权限运行latexeqedit.exe6. wps插入latex公式 1. 下载CTEX 下载CTEX网址&#xff0c;我下载的下图这个&#xff0c;下载完了之后运行exe文件安装ctex。 2. 下载LaTe…