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

news2025/2/7 20:43:36

进程间的通信–匿名管道

进程池的概念

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

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

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

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

模拟场景

通过主程序的创建,当做管理进程;然后再创建几个子进程作为资源进程,在主函数模拟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.数据丢失:如果某个写端写入速度快于其他写端,读端可能无法及时消费所有写入的数据,导致数据丢失。

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

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

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

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

相关文章

主线程捕获子线程异常

正常情况下使用多线程出现异常时&#xff0c;都是按照单个任务去处理异常&#xff0c;在线程间不需要通信的情况下&#xff0c;任务之间互不影响&#xff0c;主线程也不必知道子线程是否发成异常。 那么只需要处理子线程异常即可 Task.Run(() > {try{throw new Exception(&…

苍穹外卖学习记录(二)

本节&#xff0c;主要是学习业务逻辑&#xff0c;我们以菜品管理为例&#xff1a; 在实现这部分前&#xff0c;我们要完成Mybatis的配置&#xff0c;即指定映射的mapper.xml文件路径以及对应的实体类&#xff0c;这部分配置是在application.yml文件中实现的。 mybatis:#mapper…

计算机网络(四)网络层

网络层 基本概念 网络互联&#xff1a; 将两个以上的计算机网络&#xff0c;通过一定的办法&#xff0c;用一种或多种通信处理设备(即中间设备)相互连接起来&#xff0c;以构成更大的网络系统。中间设备又称中间系统或中继系统 中继系统分为4种&#xff1a; 物理层中继系统…

thinkphp 框架封装curl请求

tp6 或者 tp8框架 在框架的app/common.php 文件里加一些方法就可以 app\common.php 在这个文件里加 以下代码 就可以实现基于 curl的请求方法 (记得要开启 php的curl扩展) 查看方法 cmd里输入 php -m if (!function_exists(get)) {/*** 发送get请求* param string $url 请求…

ChatGPT实用指南2024

随着ChatGPT技术的演进&#xff0c;越来越多的人开始在工作中利用此工具。以下是关于ChatGPT的实用指南&#xff0c;适合不太熟悉此技术的朋友参考。 一、ChatGPT概述 1. ChatGPT是什么&#xff1f; ChatGPT是基于OpenAI开发的GPT大型语言模型的智能对话工具。它能够通过自然语…

前端框架模板

前端框架模板 1、vue-element-admin vue-element-admin是基于element-ui 的一套后台管理系统集成方案。 **功能&#xff1a;**https://panjiachen.github.io/vue-element-admin-site/zh/guide/#功能 **GitHub地址&#xff1a;**GitHub - PanJiaChen/vue-element-admin: :t…

网盘——添加好友

关于添加好友&#xff0c;过程如下&#xff1a; A、首先客户端A发送加好友的请求&#xff0c;发送的信息包括双方的用户名 B、当服务器收到请求之后&#xff0c;服务器将数据库中在线用户查找出来&#xff0c;如果客户端B已经是你的好友了&#xff0c;服务器告诉客户端A他已经…

【深度学习】深度学习md笔记总结第5篇:神经网络与tf.keras,学习目标【附代码文档】

深度学习笔记完整教程&#xff08;附代码资料&#xff09;主要内容讲述&#xff1a;深度学习课程&#xff0c;深度学习介绍要求,目标,学习目标,1.1.1 区别,学习目标,学习目标。TensorFlow介绍&#xff0c;2.4 张量学习目标,2.4.1 张量(Tensor),2.4.2 创建张量的指令,2.4.3 张量…

Sublime Text下载,安装,安装插件管理器,下载汉化插件

SublimeTest官网 © Sublime Text中文网 下载安装 一路点击安装即可 安装插件管理器 管理器官网安装 - 包控制 (packagecontrol.io) 手动安装将3 位置点击网址下载 再打开SublimeTest 点击 选择第一个Browse Packages..... 将会跳转到文件夹中 进入上一个文件夹 在进入…

【模拟】Leetcode 提莫攻击

题目讲解 495. 提莫攻击 算法讲解 前后的两个数字之间的关系要么是相减之差 > 中毒时间 &#xff0c;要么反之 那即可通过示例&#xff0c;进行算法的模拟&#xff0c;得出上图的计算公式 class Solution { public:int findPoisonedDuration(vector<int>& time…

MySql 安装,小白也可以学会成功安装的保姆级教程

MySql 安装 文章目录 MySql 安装1.Mysql下载1.1 访问下载链接1.2 选择合适版本1.3 下载安装包 2.MySql安装3.安装成功检测验证3.1 mysql自带控制台验证3.2 win系统控制台进入验证 4. mysql 配置path5. navicat 连接 mysql 1.Mysql下载 1.1 访问下载链接 MySQL Downloads 这里…

定时器、PWM定时器、UART串口通信

我要成为嵌入式高手之4月15日ARM第八天&#xff01;&#xff01; ———————————————————————————— 定时器 S3C2440A 有 5 个 16 位定时器。其中定时器 0、1、2 和 3 具有脉宽调制&#xff08;PWM&#xff09;功能。定时器 4 是一个无 输出引脚的内部…

电商技术揭秘二十五:电商平台的智能库存管理与优化

相关系列文章 电商技术揭秘一&#xff1a;电商架构设计与核心技术 电商技术揭秘二&#xff1a;电商平台推荐系统的实现与优化 电商技术揭秘三&#xff1a;电商平台的支付与结算系统 电商技术揭秘四&#xff1a;电商平台的物流管理系统 电商技术揭秘五&#xff1a;电商平台…

【DM8】ET SQL性能分析工具

通过统计SQL每个操作符的时间花费&#xff0c;从而定位到有性能问题的操作&#xff0c;指导用户去优化。 开启ET工具 INI参数&#xff1a; ENABLE_MONITOR1 MONITOR_SQL_EXEC1 查看参数 select * FROM v$dm_ini WHERE PARA_NAMEMONITOR_SQL_EXEC;SELECT * FROM v$dm_ini WH…

Fiddler工具的操作和功能时-----定位到步骤图(助力抓包)

前言&#xff1a; 继续上一篇&#xff0c;已经对fiddler的安装、配置和代理的问题进行了讲解&#xff1a; Fiddle配置代理&#xff0c;保手机模拟器访问外部网络-CSDN博客 本章&#xff0c;讲对一些fiddler的操作进行一系列讲解&#xff01;Fiddler作为一款网络调试工具&…

小型时间继电器ST3PA-C DC24V 带插座PF085A 导轨安装 JOSEF约瑟

ST3P系列时间继电器 系列型号 ST3PF-2Z(JSZ3F-2Z) 5s AC110V ST3PF(JSZ3F) 10s AC48V ST3PC-1(AH3-3) 5s DC24V ST3PC-1(AH3-3) 2h AC220V ST3PC-F(JSZ3C-F) AC380V ST3PA-E(JSZ3A-E) DC24V ST3PA-F(JSZ3A-F) DC24V ST3PF(JSZ3F) 10s AC36V ST3PC-1(AH3-3) 10s AC24V ST3PC-1…

基于SSM+Jsp+Mysql的贝儿米幼儿教育管理系统

开发语言&#xff1a;Java框架&#xff1a;ssm技术&#xff1a;JSPJDK版本&#xff1a;JDK1.8服务器&#xff1a;tomcat7数据库&#xff1a;mysql 5.7&#xff08;一定要5.7版本&#xff09;数据库工具&#xff1a;Navicat11开发软件&#xff1a;eclipse/myeclipse/ideaMaven包…

【包邮送书】MicroPython项目开发实战

欢迎关注博主 Mindtechnist 或加入【智能科技社区】一起学习和分享Linux、C、C、Python、Matlab&#xff0c;机器人运动控制、多机器人协作&#xff0c;智能优化算法&#xff0c;滤波估计、多传感器信息融合&#xff0c;机器学习&#xff0c;人工智能等相关领域的知识和技术。关…

读天才与算法:人脑与AI的数学思维笔记01_洛夫莱斯测试

1. 创造力 1.1. 创造力是一种原动力&#xff0c;它驱使人们产生新的、令人惊讶的、有价值的想法&#xff0c;并积极地将这些想法付诸实践 1.2. 创造出在表面上看似新的东西相对容易 1.3. 在遇到偶然间的创造性行为时&#xff0c;都会表现得异…

建立时间/保持时间为负是什么情况

目录 建立时间为负保持时间为负参考 在说明建立时间和保持时间为何为负的情况下&#xff0c;首先可以看看建立时间Tsu和保持时间Th的由来&#xff0c;可参考如下两篇文章&#xff1a; 建立时间和保持时间理解_为什么要满足建立时间和保持时间-CSDN博客 ic基础|时序篇&#xff…