【Linux】进程间通信_2
文章目录
- 七、进程间通信
- 1. 进程间通信分类
- 管道
- 未完待续
七、进程间通信
1. 进程间通信分类
管道
管道的四种情况:
①管道内部没有数据,并且具有写端的进程没有关闭写端,读端就要阻塞等待,知道管道pipe内部有数据。
②管道内部被写满,并且具有读端的继承没有关闭读端,写端写满管道pipe后,就需要阻塞等待,直到管道清空。
③对于写端而言:关闭了写端管道,读端会将管道pipe中的数据读完,最后会读到返回值0,表示读取完毕。
④对于读端而言:关闭了读端管道,操作系统会直接终止具有写端的进程,通过十三号信号 SIGPIPE 杀掉进程。

管道的五种特性:
①自带同步机制
②通过血缘关系进程进行通信,常见为父子进程
③pipe是面向字节流的
④父子退出,管道自动释放,文件的生命周期是随进程的
⑤管道只能单向通信
我们曾经学的命令行管道 | 本质上就是pipe。
接下来我们根据我们所学的管道知识来实现一个 进程池 。
Makefile:
processpool:processpool.ccg++ -o $@ $^ -std=c++11 -g
.PHONY:clean
clean:rm -f processpool
任务文件 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 : print log task\n" << endl;
}void ReloadConf(int fd, pid_t pid)
{cout << "sub process: " << pid << ", fd : " << fd << ", task is : reload conf task\n" << endl;
}void ConnectMysql(int fd, pid_t pid)
{cout << "sub process: " << pid << ", fd : " << fd << ", task is : connect mysql task\n" << endl;
}// 任务列表
task_t tasks[3] = {PrintLog, ReloadConf, ConnectMysql};// 随机选择一个任务
uint32_t NextTask()
{return rand() % 3;
}// 执行任务
void worker(int fd)
{while (true){uint32_t task_id = 0;ssize_t n = read(0, &task_id, sizeof(task_id));if (n == sizeof(task_id)){if (task_id >= 3) continue;tasks[task_id](fd, getpid());}else if (n == 0){cout << "sub process: " << getpid() << " exit" << endl;break;}}
}
进程池主逻辑 processpool.cc:
#include <iostream>
#include <string>
#include <unistd.h>
#include <cstdlib>
#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 << " number of processes" << endl;
}// 将信道信息封装成一个类
class Channel
{
public:Channel(int wfd, pid_t sub_id, const string &name): _wfd(wfd), _sub_process_id(sub_id), _name(name){}string name(){return _name;}int wfd(){return _wfd;}pid_t pid(){return _sub_process_id;}void Close(){close(_wfd);}~Channel() {}
private:// 信道的写端int _wfd;// 子进程的idpid_t _sub_process_id;// 信道的编号名称string _name;
};// 进程池管理类
class ProcessPool
{
public:ProcessPool(int num_processes): _num_processes(num_processes){}// 创建子进程和信道int CreateProcess(work_t work){for (int i = 0; i < _num_processes; i++){// 创建管道int pipefd[2]{0};int n = pipe(pipefd);if (n < 0)return PipeError;// 创建子进程pid_t id = fork();if (id == 0){// 这里是子进程, 读端close(pipefd[1]);// 这里需要注意的是, 子进程需要从父进程那里接收任务, 所以需要将父进程的写端重定向到标准输入dup2(pipefd[0], 0);// 子进程执行任务work(pipefd[0]);exit(0);}string cname = "Channel-" + to_string(i);// 这里是父进程, 写端close(pipefd[0]);// 放到vector中管理起来_channels.push_back(Channel{pipefd[1], id, cname});}return 0;}// 向下一个信道发送任务(目的是负载均衡)int NextChannel(){static int next = 0;int c = next++;next %= _num_processes;return c;}// 向index进程执行code任务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){// 父进程关闭写端,子进程读端读到0会自动结束进程c.Close();cout << c.name() << " close done," << " sub process id: " << c.pid() << endl;}}// 等待所有子进程退出void WaitAll(){for (auto& c : _channels){pid_t pid = c.pid();// 回收子进程返回信息pid_t rid = waitpid(pid, nullptr, 0);if (rid == pid){cout << c.name() << " sub process id: " << c.pid() << " exit done" << endl;}}}~ProcessPool() {}
private:// 进程池的大小int _num_processes;// 信道管理容器vector<Channel> _channels;
};// 控制进程池
void CtrlProcessPool(ProcessPool* pp, int cnt)
{while (cnt){// 选择通道int c = pp->NextChannel();// 选择任务uint32_t code = NextTask();// 发送任务到子进程pp->SendTaskCode(c, code);sleep(1);cnt--;}
}int main(int argc, char *argv[])
{if (argc != 2){Usage(argv[0]);return UsageError;}int num_processes = std::stoi(argv[1]);if (num_processes < 1 || num_processes > 5)return ArgError;srand((unsigned)time(nullptr));// 创建进程池对象ProcessPool* pp = new ProcessPool(num_processes);// 创建子进程和信道pp->CreateProcess(worker);// 控制子进程执行指定数量的任务CtrlProcessPool(pp, 10);// 让所有的子进程退出pp->KillAll();// 回收子进程资源pp->WaitAll();return 0;
}

未完待续
相关文章:
【Linux】进程间通信_2
文章目录 七、进程间通信1. 进程间通信分类管道 未完待续 七、进程间通信 1. 进程间通信分类 管道 管道的四种情况: ①管道内部没有数据,并且具有写端的进程没有关闭写端,读端就要阻塞等待,知道管道pipe内部有数据。 ②管道内部…...
Linux基础 - 常用命令
目录 零. 简介 一 . 常见 Ubuntu 命令 二. apt-get 下载 三. 网络命令 四. 常用命令的总结 零. 简介 在 Ubuntu 中,命令是用于与操作系统进行交互和执行各种操作的指令。通过在终端中输入命令,可以完成文件管理、系统配置、软件安装、进程管理等各种…...
轻松两步,借助向量数据库 VectorDB 与千帆 Appbuilder 构建个性化本地问答知识库
在我们日常的工作和生活中,经常会遇到需要快速获取和管理大量信息的情况。无论是解答客户的问题,还是整理公司内部的资料,一个高效的知识库系统都能帮我们省下大量时间和精力。 为了帮助大家快速构建 RAG 应用,我们之前发布了一个…...
ONLYOFFICE 桌面编辑器 8.1
ONLYOFFICE 桌面编辑器 8.1 ONLYOFFICE 简介一、轻松编辑器 PDF 文件二、用幻灯片版式快速修改幻灯片三、无缝切换文档编辑、审阅和查看模式四、**改进从右至左语言的支持 & 新的本地化选项**五、隐藏“连接到云”板块六、在演示文稿中播放视频和音频文件七、版本 8.1&…...
idea中的git在clone文件提示 filename too long
一 解决版本 1.1 问题描述以及解决办法 当在Windows系统下使用Git时出现“filename too long”错误: git config --system core.longpaths true...
C++ 数组介绍
1. 数组是什么? 在C中,数组是一种基本的数据结构,它允许我们存储固定大小的相同类型元素的集合。每个元素在数组中都有一个唯一的索引,从0开始。 2. 数组的声明与初始化 2.1 声明数组 声明数组时,需要指定数组的类…...
思维导图MindManager2024最新版,让你的思维飞起来!
亲爱的朋友们,今天我要跟大家分享一款我近期深度使用并彻底被种草的神器——MindManager2024最新版本的思维导图软件。作为一位对效率和创意有着极高追求的内容创作者,我几乎尝试过市面上所有的思维导图工具,而MindManager2024无疑是其中的佼…...
Spring容器启动流程——refresh()单个方法分析
文章目录 Spring启动过程this()方法refresh()prepareRefresh()obtainFreshBeanFactory()prepareBeanFactory()postProcessBeanFactory()invokeBeanFactoryPostProcessorsregisterBeanPostProcessorsinitMessageSource()initApplicationEventMulticaster()onRefresh()registerLi…...
Redis--注册中心集群 Cluster 集群
准备工作: 首先pull用到的镜像 docker pull redis:6.0.8 端口准备 node01 192.168.248.189.6381-6382 node02 192.168.248.190 6383-6384 node03 192.168.248.191 6385-6386 创建路径: mkdir -p /soft/docker/redis-cluster cd /soft/docker/re…...
秋招突击——6/20——复习{(单调队列优化)——最大子序列和,背包问题——宠物小精灵收服问题}——新作{两两交换链表中的节点}
文章目录 引言复习单调队列优化——最大子序列和思路分析实现代码参考实现 背包问题——宠物小精灵的收服问题个人实现参考实现 新作两两交换链表中的节点个人实现参考实现 删除有序数组中的重复项个人实现知识补全迭代器的访问和控制vector删除特定的元素erasevector底层删除元…...
使用 MongoDB 剖析开放银行:技术挑战和解决方案
开放银行(或开放金融)在银行业掀起了一股颠覆性浪潮,它迫使金融机构(银行、保险公司、金融科技公司、企业甚至政府机构)迎接一个透明、协作和创新的新时代。这种模式转变要求银行与第三方提供商(TPP&#x…...
鸿蒙 HarmonyOS NEXT星河版APP应用开发-阶段二
一、鸿蒙应用界面开发 弹性布局-Flex 语法 /* 弹性容器组件 Flex() 位置: Flex默认主轴水平往右,交叉轴垂直向下(类似Row) 语法: Flex(参数对象){子组件1,子组件2,子组件3 } 属性方法: direction…...
26.4 Django 视图层
1. 视图函数 视图函数是Django框架中用于处理Web请求并返回Web响应的重要组件. 以下是对Django视图函数的详细解释: * 1. 视图函数与URL的映射.为了让Django能够知道哪个URL对应哪个视图函数, 需要在应用的urls.py文件中定义URL模式.使用path或re_path函数来定义URL模式, 并将…...
Hbase介绍
Hbase介绍 HBase 是一个开源的、分布式的、面向列的 NoSQL 数据库系统,它建立在 Apache Hadoop 之上,提供了高可靠性、高性能、可伸缩性和高可用性的存储解决方案。让我来简单介绍一下 HBase 的架构。 1. 架构概述: HBase 的架构设计基于 Go…...
rollup学习笔记
一直使用的webpack,最近突然想了解下rollup,就花点时间学习下. 一,什么是rollup? rollup 是一个 JavaScript 模块打包器,可以将小块代码编译成大块复杂的代码,比如我们的es6模块化代码,它就可以进行tree shaking,将无用代码进行清除,打包出精简可运行的代码包. 业…...
多商户零售外卖超市外卖商品系统源码
构建你的数字化零售王国 一、引言:数字化零售的崛起 在数字化浪潮的推动下,零售业务正经历着前所未有的变革。多商户零售外卖超市商品系统源码应运而生,为商户们提供了一个全新的数字化零售解决方案。通过该系统源码,商户们可以…...
HTML 教程
HTML 教程 HTML(HyperText Markup Language)是一种用于创建网页的标准标记语言。它描述了一个网站的结构骨架,使得浏览器能够展示具有特定格式的文本、链接、图片和其他内容。本教程将带你深入了解HTML的基础知识,包括其语法、常用标签以及如何构建一个基本的网页结构。 …...
【仿真建模-解析几何】求有向线段上距指定点最近的坐标
Author:赵志乾 Date:2024-06-25 Declaration:All Right Reserved!!! 问题描述: 有向线段起点A为(x1,y1),终点B为(x2,y2&a…...
Linux系统中常用的基本命令
1. 文件与目录管理 ls: 列出目录内容。cd: 切换当前工作目录。pwd: 显示当前工作目录的路径。mkdir: 创建一个新目录。rmdir: 删除空目录。cp: 复制文件或目录。mv: 移动或重命名文件或目录。rm: 删除文件或目录。touch: 创建一个空文件或更新文件时间戳。 2. 文本内容查看 …...
数据结构与算法:回溯算法约束条件:剪枝详解、示例(C#、C++)与回溯典型例题详解
文章目录 一、约束条件二、剪枝三、典型例题四、常用术语五、示例N 皇后问题 C# 示例N 皇后问题 C 示例 六、常见用用回溯算法解决的问题汇总组合问题:图论问题:棋盘游戏问题:优化问题:调度问题:其他问题: …...
以下是对华为 HarmonyOS NETX 5属性动画(ArkTS)文档的结构化整理,通过层级标题、表格和代码块提升可读性:
一、属性动画概述NETX 作用:实现组件通用属性的渐变过渡效果,提升用户体验。支持属性:width、height、backgroundColor、opacity、scale、rotate、translate等。注意事项: 布局类属性(如宽高)变化时&#…...
python爬虫:Newspaper3k 的详细使用(好用的新闻网站文章抓取和解析的Python库)
更多内容请见: 爬虫和逆向教程-专栏介绍和目录 文章目录 一、Newspaper3k 概述1.1 Newspaper3k 介绍1.2 主要功能1.3 典型应用场景1.4 安装二、基本用法2.2 提取单篇文章的内容2.2 处理多篇文档三、高级选项3.1 自定义配置3.2 分析文章情感四、实战案例4.1 构建新闻摘要聚合器…...
《基于Apache Flink的流处理》笔记
思维导图 1-3 章 4-7章 8-11 章 参考资料 源码: https://github.com/streaming-with-flink 博客 https://flink.apache.org/bloghttps://www.ververica.com/blog 聚会及会议 https://flink-forward.orghttps://www.meetup.com/topics/apache-flink https://n…...
Selenium常用函数介绍
目录 一,元素定位 1.1 cssSeector 1.2 xpath 二,操作测试对象 三,窗口 3.1 案例 3.2 窗口切换 3.3 窗口大小 3.4 屏幕截图 3.5 关闭窗口 四,弹窗 五,等待 六,导航 七,文件上传 …...
三分算法与DeepSeek辅助证明是单峰函数
前置 单峰函数有唯一的最大值,最大值左侧的数值严格单调递增,最大值右侧的数值严格单调递减。 单谷函数有唯一的最小值,最小值左侧的数值严格单调递减,最小值右侧的数值严格单调递增。 三分的本质 三分和二分一样都是通过不断缩…...
4. TypeScript 类型推断与类型组合
一、类型推断 (一) 什么是类型推断 TypeScript 的类型推断会根据变量、函数返回值、对象和数组的赋值和使用方式,自动确定它们的类型。 这一特性减少了显式类型注解的需要,在保持类型安全的同时简化了代码。通过分析上下文和初始值,TypeSc…...
【C++】纯虚函数类外可以写实现吗?
1. 答案 先说答案,可以。 2.代码测试 .h头文件 #include <iostream> #include <string>// 抽象基类 class AbstractBase { public:AbstractBase() default;virtual ~AbstractBase() default; // 默认析构函数public:virtual int PureVirtualFunct…...
《信号与系统》第 6 章 信号与系统的时域和频域特性
目录 6.0 引言 6.1 傅里叶变换的模和相位表示 6.2 线性时不变系统频率响应的模和相位表示 6.2.1 线性与非线性相位 6.2.2 群时延 6.2.3 对数模和相位图 6.3 理想频率选择性滤波器的时域特性 6.4 非理想滤波器的时域和频域特性讨论 6.5 一阶与二阶连续时间系统 6.5.1 …...
uni-app学习笔记三十五--扩展组件的安装和使用
由于内置组件不能满足日常开发需要,uniapp官方也提供了众多的扩展组件供我们使用。由于不是内置组件,需要安装才能使用。 一、安装扩展插件 安装方法: 1.访问uniapp官方文档组件部分:组件使用的入门教程 | uni-app官网 点击左侧…...
[特殊字符] Spring Boot底层原理深度解析与高级面试题精析
一、Spring Boot底层原理详解 Spring Boot的核心设计哲学是约定优于配置和自动装配,通过简化传统Spring应用的初始化和配置流程,显著提升开发效率。其底层原理可拆解为以下核心机制: 自动装配(Auto-Configuration) 核…...
