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

【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.hqwc.cn/news/465059.html

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

相关文章

vue+springboot前后端视频文件等的上传与展示(基于七牛云)

前言&#xff1a;在初步说明完成功能之前&#xff0c;我会把重要的部分说明下。后续我会细化。 vue视频文件上传 其实这里和图片这些文件就是一样的。因为上传只是把我们想在云端展示的文件按等传输到云端的bucket。然后方便网站去请求引用。 有人问我我就说明下。这种东西无…

从Socket中解析Http协议实现通信

在网络协议中&#xff0c;Socket是连接应用层和运输层的中间层&#xff0c;主要作用为了通信。Http协议是应用层上的封装协议。我们可以通过Http协议的规范解析Socket中数据&#xff0c;完成Http通信。 首先&#xff0c;我们先回顾一下Http协议的规范。主要复习一下&#xff0c…

前端工程化面试题 | 01.精选前端工程化高频面试题

&#x1f90d; 前端开发工程师、技术日更博主、已过CET6 &#x1f368; 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 &#x1f560; 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 &#x1f35a; 蓝桥云课签约作者、上架课程《Vue.js 和 E…

JAVA设计模式之代理模式详解

代理模式 1 代理模式介绍 在软件开发中,由于一些原因,客户端不想或不能直接访问一个对象,此时可以通过一个称为"代理"的第三者来实现间接访问.该方案对应的设计模式被称为代理模式. 代理模式(Proxy Design Pattern ) 原始定义是&#xff1a;让你能够提供对象的替代…

Java String源码剖析+面试题整理

由于字符串操作是计算机程序中最常见的操作之一&#xff0c;在面试中也是经常出现。本文从基本用法出发逐步深入剖析String的结构和性质&#xff0c;并结合面试题来帮助理解。 String基本用法 在Java中String的创建可以直接像基本类型一样定义&#xff0c;也可以new一个 Str…

配备Apple T2 安全芯片的 Mac 机型及T2芯片mac电脑U盘装系统教程

T2 芯片为 Mac 提供了一系列功能&#xff0c;例如加密储存和安全启动功能、增强的图像信号处理功能&#xff0c;以及适用于触控 ID 数据的安全保护功能。哪些电脑配备了 T2 安全芯片呢&#xff0c;T2芯片mac电脑又如何重装系统呢&#xff1f;跟随小编一起来看看吧&#xff01; …

2024-2-11-复习作业

1> 要求&#xff1a; 源代码&#xff1a; #include <stdio.h> int fun(int n) {if(n0) return 1;return n*fun(n-1); } int main(int argc, char const *argv[]) {/* code */int n;printf("enter n :");scanf("%d",&n);int sfun(n);printf(…

[word] word分割线在哪里设置 #其他#经验分享

word分割线在哪里设置 在工作中有些技巧&#xff0c;可以快速提高工作效率&#xff0c;解决大部分工作&#xff0c;今天给大家分享word分割线在哪里设置的小技能&#xff0c;希望可以帮助到你。 1、快速输入分割线 输入三个【_】按下回车就是一条长直线&#xff0c;同样分别…

面向对象--静态

目录 一、静态 1.1 static修饰成员变量 1.2 static修饰成员变量的应用场景 1.3 static修饰成员方法 1.4 工具类 1.5 static的注意事项 1.6 static应用&#xff08;代码块&#xff09; 面向对象基本理解 写完会在此处放上链接 一、静态 面向对象编程中很常见的一个关键字…

一台Mac同时安装vue2和vue3

背景&#xff1a;电脑需要运行vue2和vue3项目&#xff0c;就得同时有vue2和vue3环境&#xff0c;之前以配置好vue2了&#xff0c;现在增加vue3 1. 新建一个安装vue3的目录 进入vue3文件夹安装vue3 // 注意这里没有参数-g&#xff0c;因为-g全局安装的命令 npm install vue/cli…

Jumpserver教程01:部署jumpserver

Jumpserver教程 注&#xff1a; 本教程由羞涩梦整理同步发布&#xff0c;本人技术分享站点&#xff1a;blog.hukanfa.com 转发本文请备注原文链接&#xff0c;本文内容整理日期&#xff1a;2024-02-11 csdn 博客名称&#xff1a;五维空间-影子&#xff0c;欢迎关注 简要说明…

【计算机网络】进程通信

进程 process 客户和服务器进程 下载文件表示为客户 &#xff0c;上载文件的对等方表示为服务器进程与计算机网络之间的接口 套接字 socket 应用层与传输层之间的接口是建立网络应用程序的可编程接口 API进程寻址 为了标识接收进程 需要两种信息 主机的地址目的主机中的接收进程…