Linux——进程通信(二) 匿名管道的应用:进程池

前言

之前我们学习了进程通过匿名管道进行通信,实现了两个进程的数据传输。

如果我们管理的是很多个进程,通过管道发送指令,因为如果管道中没有数据,读端必须等待,也就是被管理的进程们都在等待我发送的指令,那么我们可以通过特定的通讯方式,对进程实施控制,也就是让进程根据传输的指令去完成相应的操作。

一、进程池概念

我们知道,系统资源的获取是有成本的,比如我们创建进程,需要花一定的时间去完成,比如现在我们有一些比较重要的任务需要处理,如果等待任务到来,再创建进程去处理任务,时间上会慢一点,如果我们提前将进程创建好,任务到来,我们直接对进程分派任务,这样就能节省时间,这些提前创建好并被管理的进程,有任务来就分派执行,我们可以称之为进程池

打个比方,比如说你喝娃哈哈矿泉水,如果你感觉到口渴了,才去外面超市买娃哈哈矿泉水,这样成本是不是比较高,有点浪费时间,但是如果你提前在家里面放上一箱娃哈哈矿泉水,渴了就喝,顺手就拿的事情,效率就提高了,这也相当于把矿泉水进行池化了。

二、进程池实现

主要思路是先创建进程和信道,再发布任务,最后等待关闭父进程的写进程,让子进程read读到0,就退出子进程。最后父进程进行资源回收。

具体可以看代码注释,这里就不多BB了

ProcessPool.cpp

#include <iostream>
#include <unistd.h>
#include <cassert>
#include <cstdio>
#include <cstdlib>
#include <vector>
#include <string>
#include <sys/types.h>
#include <sys/wait.h>
#include "Task.hpp"
using namespace std;

#define NUM 5

class channel
{
public:
    channel(string name, int fd, pid_t pid)
        : _name(name), _fd(fd), _pid(pid)
    {}

public:
    string _name;
    int _fd;
    pid_t _pid;
};

void Work()
{
    while (true)
    {
        int code = 0;
        ssize_t n = read(0, &code, sizeof(code));
        if (n == sizeof(code))
        {
            if (!init.Check(code))
            {
                cout << "任务码不合法,执行失败" << endl;
                continue;
            }
            init.RunTask(code);
        }
        else if (n == 0)
            break;
    }
}

void CreatProcess(vector<channel> &v)
{
    vector<int> vfd; // 存放父进程的写信道的fd
    for (int i = 0; i < NUM; i++)
    {
        // 创建管道
        int pipefd[2];
        int n = pipe(pipefd);
        assert(n == 0);

        // 创建进程
        pid_t id = fork();
        if (id < 0)
        {
            perror("fork");
            exit(1);
        }
        // 构建信道
        else if (id == 0)
        {
            // 子进程
            vfd.push_back(pipefd[1]);
            for (auto &fd : vfd) // 关闭子进程继承的写信道
            {
                close(fd);
            }
            dup2(pipefd[0], 0);
            Work();
            exit(0);
        }
        // 父进程
        close(pipefd[0]);
        v.push_back(channel(to_string(i + 1) + "号信道", pipefd[1], id));
    }
}

void PrintChannel(const vector<channel> &v)
{
    for (auto &c : v)
    {
        cout << c._name << "," << c._fd << "," << c._pid << endl;
    }
}

void SendTask(const vector<channel> &v, bool flag, int num = 1)
{
    int pos = 0;
    while (true)
    {
        int task = init.SelectTask(); // 选择任务
        pos %= v.size();              // 选择信道轮流执行任务
        channel c = v[pos++];

        cout<<"发送信息"<<init.ToDesc(task)<<"给"<<c._name<<",pid是"<<c._pid<<endl;

        write(c._fd, &task, sizeof(task)); // 发送任务

        if (!flag)
        {
            if (--num <= 0)
                break;
        }
        sleep(1);
    }
    sleep(1);
    cout << "发送任务完成" << endl;
}

void WaitPorcess(vector<channel> v)
{
    for (auto &c : v)
    {
        close(c._fd);
        pid_t rid = waitpid(c._fd, nullptr, 0);
        cout<<"等待子进程"<<c._pid<<"成功"<<endl;
    }
}

int main()
{
    vector<channel> channels;
    // 创建进程和信道
    CreatProcess(channels);
    // PrintChannel(channels);  //打印测试

    // 发送任务
    const bool always_loop = true;
    SendTask(channels, !always_loop, 10);

    // 进程等待回收
    WaitPorcess(channels);
    return 0;
}

Task.hpp

#pragma once

#include <iostream>
#include <functional>
#include <vector>
#include <ctime>

using namespace std;

typedef function<void()> task_t;

void Download()
{
    cout << "我正在下载,"
         << "pid:" << getpid() << endl;
}

void Print()
{
    cout << "我正在打印,"
         << "pid:" << getpid() << endl;
}

void PlayVideo()
{
    cout << "我正在播放,"
         << "pid:" << getpid() << endl;
}

class Init
{
public:
    Init()
    {
        tasks.push_back(Download);
        tasks.push_back(Print);
        tasks.push_back(PlayVideo);
        srand(time(nullptr));
    }

    void RunTask(int code)
    {
        tasks[code]();
    }

    string ToDesc(int code)
    {
        switch (code)
        {
        case 0:
            return "Download";
        case 1:
            return "Print";
        case 2:
            return "PlayVideo";
        default:
            return "Unkonw";
        }
    }

    bool Check(int code)
    {
        return code >= 0 && code < tasks.size();
    }

    int SelectTask()
    {
        return rand() % tasks.size();
    }

public:
    vector<task_t> tasks;
    // 任务码
    const int download_code = 0;
    const int print_code = 1;
    const int PlayVideo_code = 2;
};

Init init;

 运行结果如下。

 

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

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

相关文章

某东联盟js逆向

声明: 本文章中所有内容仅供学习交流使用&#xff0c;不用于其他任何目的&#xff0c;不提供完整代码&#xff0c;抓包内容、敏感网址、数据接口等均已做脱敏处理&#xff0c;严禁用于商业用途和非法用途&#xff0c;否则由此产生的一切后果均与作者无关&#xff01;wx a15018…

【Web技术应用基础】HTML(2)——文本练习

题目1&#xff1a; <!DOCTYPE html> <html><head><meta charset"utf-8"><title>HTML链接</title><meta name"description" content"HTML链接知识讲解"><meta name"keywords" content&qu…

C语言经典算法-6

文章目录 其他经典例题跳转链接31.数字拆解32.得分排行33.选择、插入、气泡排序34.Shell 排序法 - 改良的插入排序35.Shaker 排序法 - 改良的气泡排序 其他经典例题跳转链接 C语言经典算法-1 1.汉若塔 2. 费式数列 3. 巴斯卡三角形 4. 三色棋 5. 老鼠走迷官&#xff08;一&…

HTML5+CSS3小实例:具有悬停效果的3D闪耀动画

实例:具有悬停效果的3D闪耀动画 技术栈:HTML+CSS 效果: 源码: 【HTML】 <!DOCTYPE html> <html lang="zh-CN"> <head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, init…

Python 第三方库(Tiptop\Rembg)

Tiptop 简介 tiptop:命令行系统监控工具 Tiptop 安装 1、创建虚拟环境photemaker, 并激活photemaker. 2、安装tiptop, 执行如下指令: pip install tiptop 3、执行效果 Tiptop 命令执行遇到的问题 在CMD 控制台执行tiptop 命令&#xff0c;提示如下报错&#xff1a; ──…

【Docker篇】数据卷相关操作

文章目录 &#x1f388;前言&#x1f354;数据卷&#x1f6f8;操作命令⭐创建一个数据卷&#xff0c;并查看数据卷在宿主机的目录位置 &#x1f339;挂载数据卷 &#x1f388;前言 在前面文章的nginx案例中&#xff0c;修改nginx的html页面时&#xff0c;需要进入nginx内部。并…

【sequence进阶 config_db message_2024.03.14】

sequence进阶 sequence的仲裁 多个sequence发送给一个sequencer的情况&#xff0c;使用的两种方式&#xff1a; class virtual_seqence extends uvm_sequence;virtual task body();sub_sequene seq_0;sub_sequene seq_1;//第一种方式p_sequencer.apb_mst_sqr.set_arbitratio…

【机器学习】基于机器学习的分类算法对比实验

摘要 基于机器学习的分类算法对比实验 本论文旨在对常见的分类算法进行综合比较和评估&#xff0c;并探索它们在机器学习分类领域的应用。实验结果显示&#xff0c;随机森林模型在CIFAR-10数据集上的精确度为0.4654&#xff0c;CatBoost模型为0.4916&#xff0c;XGBoost模型为…

Android视角看鸿蒙第六课(module.json5中的各字段含义之pages)designWidth的用法

Android视角看鸿蒙第六课(module.json5中的各字段含义之pages&#xff09; 导读 前面几篇文章&#xff0c;我们陆续分析了entry->src->main下的module.json5中的各个字段的含义及作用。目前剩余pages和abilities两个字段&#xff0c;本篇文章一起来了解pages。 过程有错…

递归算法c++

主页:(*∇&#xff40;*) 咦,又好了~ xiaocr_blog 算法概述&#xff1a;递归算法是一种直接或者间接调用自身函数或者方法的算法。说简单了就是程序自身的调用。 算法实质&#xff1a;递归算法就是将原问题不断分解为规模缩小的子问题&#xff0c;然后递归调用方法来表示问题的…

[C语言]指针详解一、数组指针、二维数组传参、函数指针

一、数组指针 对一个数组&#xff0c;如果我们想要让一个指针指向这个数组&#xff0c;我们应该如何定义呢?我们知道一个数组定义本来就是一个指针&#xff0c;那为何要多定义一个数组指针呢?我们来看看下面这个代码就理解了 #include <stdio.h> int main() {int arr…

Docker与containerd:容器技术的双璧

&#x1f407;明明跟你说过&#xff1a;个人主页 &#x1f3c5;个人专栏&#xff1a;《Docker幻想曲&#xff1a;从零开始&#xff0c;征服容器宇宙》 &#x1f3c5; &#x1f516;行路有良友&#xff0c;便是天堂&#x1f516; 目录 一、前言 1、Docker和containerd的背景…

SpringBoot如何优雅实现远程调用

微服务之间的通信方式 常见的方式有两种&#xff1a; RPC——代表-dubbo HTTP——代表-SpringCloud 在SpringCloud中&#xff0c;默认是使用http来进行微服务的通信&#xff0c;最常用的实现形式有两种&#xff1a; RestTemplate Feign

深度学习_ResNet_5

ResNet学习目标 什么是ResNet为什么要引入ResNet&#xff1f;ResNet网络结构的特点利用ResNet完成图像分类 什么是ResNet&#xff1f; ResNet&#xff08;Residual Network&#xff09;是一种深度残差网络&#xff0c;由何凯明等人在2015年提出&#xff0c;是深度学习领域中一…

Gartner发布安全运营指南:迈向卓越安全运营的 5 项举措

顶级组织通常会实施一套通用的安全运营活动&#xff0c;以实现成熟&#xff0c;但是&#xff0c;他们在应对快速发展的威胁方面仍然面临挑战。安全和风险管理领导者可以利用这五项举措来加强他们的网络防御工作&#xff0c;同时促进安全投资的更大回报。 主要发现 旨在提升威胁…

【Java多线程】面试常考 —— JUC(java.util.concurrent) 的常见类

目录 1、JUC&#xff08;java.util.concurrent&#xff09; 1.1、Callable 接口 1.2、ReentrantLock 可重入锁 1.3、Semaphore 信号量 1.4、CountDownLatch 1、JUC&#xff08;java.util.concurrent&#xff09; 这是java中的一个包&#xff0c;存放着多线程编程中常见的…

电机学(笔记一)

磁极对数p&#xff1a; 直流电机的磁极对数是指电机定子的磁极对数&#xff0c;也等于电机电刷的对数。它与电机的转速和扭矩有直接关系。一般来说&#xff0c;极对数越多&#xff0c;电机转速越低&#xff0c;扭矩越大&#xff0c;适用于低速、高扭矩的场合&#xff1b;相反&…

MATLAB的使用(一)

一&#xff0c;MATLAB的编程特点 a,语法高度简化&#xff1b; b,脚本式解释型语言&#xff1b; c,针对矩阵的高性能运算&#xff1b; d,丰富的函数工具箱支持&#xff1b; e,通过matlab本体构建跨平台&#xff1b; 二&#xff0c;MATLAB的界面 工具栏:提供快捷操作编辑器…

HCIP的学习(2)

TCP----传输控制协议 是一种面向连接的可靠传输协议。 注&#xff1a;与我之前博客HCIA的学习&#xff08;2&#xff09;结合一起看 面向连接&#xff1a;数据传输前收发双方建立一条逻辑通路 特点&#xff1a; TCP是一种面向连接的传输协议每一条TCP连接有且只能存在两个端…

kafka2.x版本配置SSL进行加密和身份验证

背景&#xff1a;找了一圈资料&#xff0c;都是东讲讲西讲讲&#xff0c;最后我还没搞好&#xff0c;最终决定参考官网说明。 官网指导手册地址&#xff1a;Apache Kafka 先只看SSL安全机制方式。 Apache Kafka 允许客户端通过 SSL 进行连接。默认情况下&#xff0c;SSL 处于…