【Linux进程间通信】用管道实现简单的进程池、命名管道

news2024/11/26 0:38:45

【Linux进程间通信】用管道实现简单的进程池、命名管道

目录

  • 【Linux进程间通信】用管道实现简单的进程池、命名管道
    • 为什么要实现进程池?
    • 代码实现
      • 命名管道
        • 创建一个命名管道
      • 理解命名管道
        • 匿名管道与命名管道的区别
        • 命名管道的打开规则

作者:爱写代码的刚子

时间:2024.2.10

前言:本篇博客将会介绍并实现简单的线程池

为什么要实现进程池?

  • 系统调用是有成本的,池化技术是为了我们的访问速度和效率
  • 在需要频繁的创建删除较多进程的情况下,导致计算机资源消耗过多
  • 进程池则是创建指定进程数量等待执行事件,避免了不必要的创建和销毁过程

代码实现

  • ProcessPool_Task.hpp
#pragma once

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

using task_t=std::function<void()>;
//typedef void(*task_t)();
void task1()
{
    std::cout<<"task1"<<std::endl;
}

void task2()
{
    std::cout<<"task2"<<std::endl;
}

void task3()
{
    std::cout<<"task3"<<std::endl;
}

void task4()
{
    std::cout<<"task4"<<std::endl;
}

void LoadTask(std::vector<task_t> *tasks)
{
    tasks->push_back(task1);
    tasks->push_back(task2);
    tasks->push_back(task3);
    tasks->push_back(task4);

}
  • ProcessPool.cc
#include "ProcessPool_Task.hpp"
#include <string>
#include <vector>
#include <ctime>
#include <unistd.h>
#include <cstdlib>
#include <cassert>
#include <iostream>

#include <sys/wait.h>
#include <sys/stat.h>

const int processnum = 5;
//描述

std::vector<task_t> tasks;
class channel
{ 
public:
    channel(int cmdfd,int slaverid,const std::string &processname)
    :_cmdfd(cmdfd),_slaverid(slaverid),_processname(processname)
    {}

public:
    int _cmdfd;
    pid_t _slaverid;
    std::string _processname;
};


void slaver()
{
    while(true)
    {
        int cmdcode = 0;
        int n = read(0,&cmdcode, sizeof(int));//如果父进程不给子进程发送数据,则会阻塞等待
        if(n == sizeof(int))
        {
            //执行cmdcode对应的任务列表
            std::cout <<"slaver say@ get a command: "<<getpid() << ": cmdcode: "<< cmdcode <<std::endl;
            if(cmdcode >=0 && cmdcode<tasks.size()) tasks[cmdcode]();
        }
        if(n == 0)break;
    }
}
//参数规范
//输入:const &
//输出:*
//输入输出:&


void InitProcessPool(std::vector<channel> *channels)
{
    //确保每一个子进程都只有一个写端
    std::vector<int> oldfds;
    for(int i=0;i<processnum;++i)
    {
        int pipefd[2];//临时空间
        int n = pipe(pipefd);
        assert(!n);
        (void)n;


        
        pid_t id = fork();
        if(id==0)//子进程,子进程拿到的pipefd都是3
        {
            std::cout<< "child" << getpid() << "close history fd: ";
            for(auto fd : oldfds) 
            {
                std::cout<<fd<<" ";
                close(fd);
            }
            std::cout<<"\n";
            close(pipefd[1]);
            dup2(pipefd[0],0);//将pipefd[0]重定向到0,将来直接往键盘文件(fd为0)文件里面读即可。
            close(pipefd[0]);
            
            slaver();
            std::cout<< "process : "<< getpid() << "quit" <<std::endl;
            //方法一:
            //slaver(pipefd[0]);
            exit(0);
        }
        //父进程,父进程拿到的pipefd是4,5,6...
        close(pipefd[0]);

        //添加channel字段
        std::string name = "process-"+ std::to_string(i);
        channels->push_back(channel(pipefd[1],id,name ));//pipefd[1]表示父进程要往pipefd[1]里面写
        oldfds.push_back(pipefd[1]);
    }
}

void Debug(const std::vector<channel> &channels)
{
    for(const auto &c : channels)
    {
        std::cout<<c._cmdfd<<" "<<c._slaverid<<" "<<c._processname << std::endl;
    }
}

void ctrlSlaver(const std::vector<channel> &channels)
{
    int which = 0;//轮转的方式
    while(true)
    {
        //1.选择任务
        int cmdcode = rand()%tasks.size();

        //2.选择进程
        //[负载均衡(1.随机数 2.轮转)]
        int processpos = rand()%channels.size();

        //3.发送任务
        write(channels[which]._cmdfd,&cmdcode,sizeof(cmdcode));
        
        ++which;
        which %= channels.size();
        
        sleep(1);
    }
}

void QuitProcess(const std::vector<channel> &channels)
{
    //for(const auto &c : channels) close(c._cmdfd);
    //for(const auto &c : channels) waitpid(c._slaverid,nullptr,0);
    //这里存在子进程有多个写端的问题,解决办法:
    //方法一.从后往前关闭子进程
    int last = channels.size()-1;
    for(int i= last;i>= 0;i--)
    {
        close(channels[i]._cmdfd);
        waitpid(channels[i]._slaverid,nullptr,0);
    }
    //方法二.确保每一个子进程都只有一个写端

}
int main()
{
    
    LoadTask(&tasks);
    //随机数
    srand(time(nullptr)^getpid()^1023);
    //组织
    std::vector<channel> channels;//将特定的结构转化为数据的增删查改
    //初始化
    InitProcessPool(&channels);
    Debug(channels);
    //控制子进程
    ctrlSlaver(channels);
    //清理收尾
    QuitProcess(channels);

    return 0;
}

图解:

在这里插入图片描述

命名管道

  • 管道应用的一个限制就是只能在具有共同祖先(具有亲缘关系)的进程间通信。

  • 如果我们想在不相关的进程之间交换数据,可以使用FIFO文件来做这项工作,它经常被称为命名管道。

  • 命名管道是一种特殊类型的文件

创建一个命名管道
  • $ mkfifo filename在命令行上创建命名管道

在这里插入图片描述

p开头表示这是命名管道(但是并不在磁盘上),同时管道文件的大小为0

在这里插入图片描述

  • *int mkfifo(const char filename, mode_t mode); 程序中创建命名管道的函数

理解命名管道

不同的两个进程打开同一个文件的时候,在内核中操作系统文件描述符只会指向同一个文件,进程间通信的前提:先让不同的进程看到同一份资源,管道文件则不需要进行刷盘(内存级文件),所以大小为0字节。

【问题】:如何保证打开的是同一个文件?看到同一个路径下的同一个文件名。(inode),即= 路径 + 文件名(唯一性)

匿名管道与命名管道的区别

匿名管道由pipe函数创建并打开。

命名管道由mkfifo函数创建,打开用open

FIFO(命名管道)与pipe(匿名管道)之间唯一的区别在它们创建与打开的方式不同,一但这些工作完成之后,它们具有相同的语义。

命名管道的打开规则
  • 如果当前打开操作是为读而打开FIFO时

    • O_NONBLOCK disable:阻塞直到有相应进程为写而打开该FIFO
    • O_NONBLOCK enable:立刻返回成功
  • 如果当前打开操作是为写而打开FIFO时

    • O_NONBLOCK disable:阻塞直到有相应进程为读而打开该FIFO
    • O_NONBLOCK enable:立刻返回失败,错误码为ENXIO

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

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

相关文章

LLM之RAG实战(二十五)| 使用LlamaIndex和BM25重排序实践

本文&#xff0c;我们将研究高级RAG方法的中的重排序优化方法以及其与普通RAG相比的关键差异。 一、什么是RAG&#xff1f; 检索增强生成&#xff08;RAG&#xff09;是一种复杂的自然语言处理方法&#xff0c;它包括两个不同的步骤&#xff1a;信息检索和生成语言建模。这种方…

ShardingSphere 5.x 系列【7】元数据持久化

有道无术,术尚可求,有术无道,止于术。 本系列Spring Boot 版本 3.1.0 本系列ShardingSphere 版本 5.4.0 源码地址:https://gitee.com/pearl-organization/study-sharding-sphere-demo 文章目录 1.概述2. 单机模式2.1 H22.2 MySQL3. 集群模式3.1 ZooKeeper3.2 Nacos3.3 Co…

第十八篇【传奇开心果短博文系列】Python的OpenCV库技术点案例示例:图像修复和恢复

传奇开心果短博文系列 系列短博文目录Python的OpenCV库技术点案例示例系列短博文目录前言一、常用的图像修复与恢复技术二、插值方法示例代码三、基于纹理合成的方法示例代码四、基于边缘保持的方法示例代码五、基于图像修复模型的方法示例代码六、基于深度学习的方法示例代码七…

基于centos的Linux中如何安装python

前言 之前在linux上安装python的时候没来及记录下来&#xff0c;感觉还是有必要的&#xff0c;所以现在打算把原来装好的python卸载掉&#xff0c;然后重装一遍&#xff0c;重新记录一下。当前环境是否安装python 通过查询我发现机器里有3个版本的python&#xff0c;第一个是…

《杨绛传:生活不易,保持优雅》读书摘录

目录 书简介 作者成就 书中内容摘录 良好的家世背景&#xff0c;书香门第为求学打基础 求学相关 念大学 清华研究生 自费英国留学 法国留学自学文学 战乱时期回国 当校长 当小学老师 创造话剧 支持钱锺书写《围城》 出任震旦女子文理学院的教授 接受清华大学的…

【开源】SpringBoot框架开发APK检测管理系统

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 数据中心模块2.2 开放平台模块2.3 软件档案模块2.4 软件检测模块2.5 软件举报模块 三、系统设计3.1 用例设计3.2 数据库设计3.2.1 开放平台表3.2.2 软件档案表3.2.3 软件检测表3.2.4 软件举报表 四、系统展示五、核心代…

C++中类的6个默认成员函数【构造函数】 【析构函数】

文章目录 前言构造函数构造函数的概念构造函数的特性 析构函数 前言 在学习C我们必须要掌握的6个默认成员函数&#xff0c;接下来本文讲解2个默认成员函数 构造函数 如果一个类中什么成员都没有&#xff0c;简称为空类。 空类中真的什么都没有吗&#xff1f;并不是&#xff0c…

嵌入式硬件越老越吃香,确实没错!

不知不觉已经从事硬件设计7年多了&#xff0c;7年对于一个从事硬件设计来说能有几个完整的生涯。2016年毕业&#xff0c;2023年即将结束&#xff0c;我已经在汽车这行业“摸爬滚打”了7年的时光。 回顾这7年&#xff0c;自己真的成长了很多很多。有项目失败整改的经验收获&…

java实现文件随机加密

1、引言 有时候我们需要对我们的某些文件数据进行加密&#xff0c;并且不希望被轻易破译&#xff0c;此时最好不要使用已知的加密方法&#xff0c;这里我就给大家提供一种数据加密的方式&#xff0c;用以实现文件数据的加密&#xff0c;我称之为随机加密&#xff0c;即使是对相…

【FPGA】Verilog:奇偶校验位发生器 | 奇偶校验位校验器

目录 0x00 奇偶校验位发生器 0x01 奇偶校验位校验器 0x02 错误检测器和纠错器

Failed to construct ‘RTCIceCandidate‘ sdpMid and sdpMLineIndex are both null

最近在搞webrtc&#xff0c;在编写函数处理远端传递来的candidate时报错了&#xff0c;具体信息如下。国内关于webrtc的资料很少&#xff0c;所以去国外社区转了一圈&#xff0c;回来记录一下报错的解决方案 其实这个bug也好解决&#xff0c;根据报错信息可以判断是RTCIceCand…

数据结构(2) 线性表

线性表 线性表的定义线性表的基本操作lnitList(&L)DestroyList(&L)Listlnsert(&L,i,e)ListDelete(&L,i,&e)LocateElem(L,e)GetElem(L,i)Length(L)PrintList(L)Empty(L)Tips:引用值 小结 根据数据结构的三要素–逻辑结构、数据的运算、存储结构&#xff0c;…

第78讲 修改密码

系统管理实现 修改密码实现 前端 modifyPassword.vue&#xff1a; <template><el-card><el-formref"formRef":model"form":rules"rules"label-width"150px"><el-form-item label"用户名&#xff1a;&quo…

Game辅助推广购卡系统全新一键安装版-已激活

(购买本专栏可免费下载栏目内所有资源不受限制,持续发布中,需要注意的是,本专栏为批量下载专用,并无法保证某款源码或者插件绝对可用,介意不要购买) 资源简介 运行环境 PHP5.6~7.0+MYSQL5.6 本程序可配合(伯乐发卡)基础版使用; 界面炫酷大气!程序内核为yunucm…

智能时代:创新创业的新机遇与挑战

智能时代为创新创业提供了广阔的空间和无限的可能性。以下是一些可能适合智能时代背景的创新创业方向&#xff1a; 人工智能技术应用&#xff1a;人工智能技术是当前科技领域最热门的技术之一&#xff0c;其应用范围不断扩大。创业者可以将人工智能技术应用于各个领域&#xf…

Netty应用(五) 之 Netty引入 EventLoop

目录 第三章 Netty 1.什么是Netty&#xff1f; 2.为什么需要使用Netty&#xff1f; 3.Netty的发展历程 4.谁在使用Netty&#xff1f; 5.为什么上述这些分布式产品都使用Netty&#xff1f; 6.第一个Netty应用 7.如何理解Netty是NIO的封装 8.logback日志使用的加强 9.Ev…

特殊形势下如何自主创新创业

当下的经济形势相信每个人都有不断的判断&#xff0c;但比较一致的观点是经济下行趋势十分明显&#xff0c;无论是传统的建筑以及相应的建材、家居、家电行业&#xff0c;还是曾红极一时的IT行业&#xff0c;甚至是芯片业行&#xff0c;都出现了严重的需求不足、产能过剩。从而…

AI:125-基于深度学习的航拍图像中地物变化检测

🚀点击这里跳转到本专栏,可查阅专栏顶置最新的指南宝典~ 🎉🎊🎉 你的技术旅程将在这里启航! 从基础到实践,深入学习。无论你是初学者还是经验丰富的老手,对于本专栏案例和项目实践都有参考学习意义。 ✨✨✨ 每一个案例都附带有在本地跑过的关键代码,详细讲解供…

【深度学习:语义分割】语义分割简介

【深度学习&#xff1a;语义分割】语义分割简介 什么是图像分割&#xff1f;了解语义分割数据采集语义分割的深度学习实现全卷积网络上采样跳跃连接U-NetDeepLab多尺度物体检测金字塔场景解析网络&#xff08;PSPNet&#xff09; 语义分割的应用医学影像自动驾驶汽车农业图片处…

《Git 简易速速上手小册》第7章:处理大型项目(2024 最新版)

文章目录 7.1 Git Large File Storage (LFS)7.1.1 基础知识讲解7.1.2 重点案例&#xff1a;在 Python 项目中使用 Git LFS 管理数据集7.1.3 拓展案例 1&#xff1a;使用 Git LFS 管理大型静态资源7.1.4 拓展案例 2&#xff1a;优化现有项目中的大文件管理 7.2 性能优化技巧7.2.…