从零开始学习管道:管道程序的优化和文件描述符继承问题

📟作者主页:慢热的陕西人

🌴专栏链接:Linux

📣欢迎各位大佬👍点赞🔥关注🚓收藏,🍉留言

本博客主要内容管道后续的完善,以及解决管道继承多个文件描述符的问题

文章目录

    • 1.管道程序的再优化
      • 1.1void ctrlprocess函数
      • 1.2EndPoint类
      • 1.3RecailmTask函数
      • 1.4子进程继承父进程文件描述符问题的解决

1.管道程序的再优化

1.1void ctrlprocess函数

分三步:

  • 确定任务
  • 确定执行任务的子进程.轮询式的
  • 执行任务
void ctrlprocess(const vector<EndPoint>& end_points)
{// 2.写成自动化,也可以搞成交互式的int cnt = 0;while (true){//1.确定任务int command = ShowBoard();if(command == 3) break;if(command < 0 || command > 2) continue;//2.确定执行任务的子进程.轮询式的int child = cnt++;cnt %= end_points.size();cout << "选择了进程:" << end_points[child].name() <<"| 处理任务:" << command << endl;//3.执行任务write(end_points[child]._write_fd, &command, sizeof(command));sleep(1);}
}

1.2EndPoint类

  • 增加static成员number:用于统计子进程个数
  • 增加string processname:用于存储进程的名字
  • 增加name函数:用于打印子进程的名字
// 先描述
class EndPoint
{
private:static int number;
public:pid_t _child;  // 子进程pidint _write_fd; // 对应的文件描述符string processname;
public:// 构造EndPoint(int id, int fd): _child(id), _write_fd(fd){char namebuffer[64];snprintf(namebuffer, sizeof(namebuffer), "process-%d[%d:%d]", number++, id, fd);processname = namebuffer;}string name() const {return processname;}// 析构~EndPoint(){}
};

1.3RecailmTask函数

用于子进程的回收:

  • ①关闭写描述符:根据前面讲的父进程关闭了管道对应的写描述符之后,子进程也就退出了
  • ②回收子进程:waitpid对应的函数进行回收!

方案一:两种操作分开执行

void RecailmTask(const vector<EndPoint>& end_points)
{//1.关闭写描述符for(int i = 0; i < end_points.size(); ++i) close(end_points[i]._write_fd);cout << "父进程让所有的进程退出了" << endl;sleep(5);//2.回收子进程for(int i = 0; i < end_points.size(); ++i) waitpid(end_points[i]._child, nullptr, 0);sleep(5);
}

运行结果:

子进程在父进程的操控下,正常退出了

image-20231126215109563

1.4子进程继承父进程文件描述符问题的解决

但是当我们把这两个过程合并的时候问题出现了:

然后就卡住了

void RecailmTask(const vector<EndPoint>& end_points)
{//1.关闭写描述符for(int i = 0; i < end_points.size(); ++i) {close(end_points[i]._write_fd);waitpid(end_points[i]._child, nullptr, 0);}cout << "父进程让所有的进程退出了" << endl;sleep(5);
}

image-20231126220145423

这是为什么呢?其实我们想一想,父进程在创建子进程的时候子进程也会把父进程的文件描述符也会拷贝一份

image-20231126221535592

所以除了第一个子进程当我们父进程关闭对应的写端的时候子进程不会关闭,原因是其他的子进程也继承了对应的写端的文件描述符。所以写端并没有完全关闭,所以这时候父进程去等待回收子进程的时候就会一直在等待,造成了程序卡住的状态!那么我们怎么解决呢?

方案一:反着顺序关闭写端

void RecailmTask(const vector<EndPoint>& end_points)
{//1.关闭写描述符for(int end = end_points.size() - 1; end >= 0; --end) {close(end_points[end]._write_fd);waitpid(end_points[end]._child, nullptr, 0);}cout << "父进程让所有的进程退出了" << endl;sleep(5);
}

image-20231126222855900

可是我们这种办法只是解决了表象,我们没有解决的根本的情况,我们只是让程序可以正常的关闭,但是子进程的那种继承父进程管道的文件描述符的问题还是没有解决,并且这也是有一定不安全的情况在里面的,因为管道不是一对一的情况了,变成了多对一的情况,可能会造成其他的子进程向其他管道中错误写入的问题:

所以我们我解决这个问题,这个问题我们应该在创建子进程管道的时候就解决好!

思路:我们每创建一个子进程,把其对应的文件描述符存储在一个vector内部,然后再创建第二个子进程的时候,遍历vector的时候,将他们依次关掉即可!

void creatProcesses(vector<EndPoint> &end_points)
{//用于存储文件描述符vector<int>fds;// 1.先进行构建控制结构,父进程写,子进程读for (int i = 0; i < gnum; ++i){// 1.1创建管道int pipefd[2] = {0};int ret = pipe(pipefd);assert(ret == 0); // 0正常 -1不正常(void)ret;// 1.2创建进程pid_t id = fork();assert(id != -1);if (id == 0){//关闭不必要的描述符for(auto& fd : fds) close(fd);// 子进程// 1.3关闭不要的fdclose(pipefd[1]);// 我们期望,所有的子进程读取“指令”的时候,都从标准输入读取// 1.3.1所以我们进行输入重定向dup2(pipefd[0], 0);// 1.3.2子进程开始等待获取命令WaitCommend();close(pipefd[0]);exit(0);}// 父进程// 1.3关闭不要的fdclose(pipefd[0]);// 1.4将新的子进程和他的管道写端构建对象。end_points.push_back(EndPoint(id, pipefd[1]));fds.push_back(pipefd[1]);}
}

运行结果:

image-20231126224519572


到这本篇博客的内容就到此结束了。
如果觉得本篇博客内容对你有所帮助的话,可以点赞,收藏,顺便关注一下!
如果文章内容有错误,欢迎在评论区指正

在这里插入图片描述

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

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

相关文章

【Amazon】基于Amazon提供的托管式EKS通过eksctl命令部署Kubernetes集群

文章目录 一、使用CloudFormation创建堡垒机二、安装AWS CLI命令行工具三、安装eksctl命令行工具四、创建集群角色4.1 集群服务角色创建4.2 集群节点组角色创建 五、创建 EKS集群六、登录EKS控制台七、参考链接 一、使用CloudFormation创建堡垒机 导航至CloudFormation&#xf…

python类和对象

1.使用对象组织数据 class Student:nameNone #记录名字 stu1Student() #创建对象 stu1.name"abc" #为对象属性赋值2.类的定义和使用 2.1成员方法的定义语法 传参的时候self是透明的&#xff0c;不用管 class Stu:nameNonedef sayHi(self):print(f"你好&#x…

【数据中台】开源项目(1)-LarkMidTable

LarkMidTable 是一站式开源的数据中台&#xff0c;实现中台的 基础建设&#xff0c;数据治理&#xff0c;数据开发&#xff0c;监控告警&#xff0c;数据服务&#xff0c;数据的可视化&#xff0c;实现高效赋能数据前台并提供数据服务的产品。 系统演示地址 &#xff1a; www.l…

Windows 7隐藏用户测试

请注意Window 7是在虚拟机上安装的&#xff0c;ip是192.168.0.108。 下边都是在虚拟机Window 7上操作&#xff0c;直到最后远程连接才在自己本机Windows 11上操作。 需要同时按下Windowsr,然后输入cmd&#xff0c;再点击确定。 在命令上里边输入net user可以显示一下用户。 …

C语言学习笔记之函数篇

与数学意义上的函数不同&#xff0c;C语言中的函数又称为过程&#xff0c;接口&#xff0c;具有极其重要的作用。教科书上将其定义为&#xff1a;程序中的子程序。 在计算机科学中&#xff0c;子程序&#xff08;英语&#xff1a;Subroutine, procedure, function, routine, me…

React 入门使用 (官方文档向 Part2)

文章目录 用 State 响应输入声明式地考虑 UI步骤 1&#xff1a;定位组件中不同的视图状态步骤 2&#xff1a;确定是什么触发了这些状态的改变步骤 3&#xff1a;通过 useState 表示内存中的 state步骤 4&#xff1a;删除任何不必要的 state 变量步骤 5&#xff1a;连接事件处理…

059-第三代软件开发-巧用工控板LED指示灯引脚

第三代软件开发-巧用工控板LED指示灯引脚 文章目录 第三代软件开发-巧用工控板LED指示灯引脚项目介绍巧用工控板LED指示灯引脚第一种方式第二种方式 总结 关键字&#xff1a; Qt、 Qml、 Power、 继电器、 IO 项目介绍 欢迎来到我们的 QML & C 项目&#xff01;这个项…

video标签在h5中被劫持问题

将video的视频链接转为blob export const encryptionVideo (options: URL) > {return new Promise((resolve, reject) > {window.URL window.URL || window.webkitURL;var xhr new XMLHttpRequest();xhr.open(GET, options.url, true);xhr.responseType blob;xhr.onl…

圆通速递单号查询入口,以表格的形式导出详细物流信息

批量查询圆通速递单号的物流信息&#xff0c;并以表格的形式导出单号的详细物流信息。 所需工具&#xff1a; 一个【快递批量查询高手】软件 圆通速递单号若干 操作步骤&#xff1a; 步骤1&#xff1a;运行【快递批量查询高手】软件&#xff0c;第一次使用的伙伴记得先注册&…

C++初识类和对象

前言 上一期我们介绍了一些C入门的基础知识&#xff0c;本期我们来介绍面向对象。初步认识一下面向对象和面向过程、类、以及封装&#xff01; 本期内容介绍 面向过程和面向对象 类的引入 类的定义 类的访问限定符和封装 类的作用域 类的实例化 类对象模型 this指针 一、面向…

基本数据结构二叉树(1)

目录 1.树概念及结构 1.1树的概念 1.2 树的相关概念 1.3 树的表示 1.4 树在实际中的运用&#xff08;表示文件系统的目录树结构&#xff09; 2.二叉树概念及结构 2.1概念 2.2现实中的二叉树&#xff1a; 2.3 特殊的二叉树&#xff1a; 2.5 二叉树的存储结构 2. 链式存…

【多线程】-- 03 龟兔赛跑案例线程创建方法之三:Callable接口

多线程 2 线程创建 【续】2.2 龟兔赛跑案例 首先需要一个赛道距离&#xff0c;然后会距离终点越来越近判断比赛是否结束打印出胜利者龟兔赛跑开始故事中是乌龟获胜&#xff0c;兔子需要睡觉&#xff0c;所以要模拟兔子睡觉最终&#xff0c;乌龟赢得比赛 package com.duo.de…

C语言数据类型和变量

# C语言数据类型和变量 # 数据类型介绍 C语⾔提供了丰富的数据类型来描述⽣活中的各种数据。使⽤整型类型来描述整数&#xff0c;使⽤字符类型来描述字符&#xff0c;使⽤浮点型类型来描述⼩数。所谓“类型”&#xff0c;就是相似的数据所拥有的共同特征&#xff0c;编译器只有…

MySQL进阶知识

目录 MySQL的Linux安装 存储引擎 MySQL的体系结构 存储引擎简介 存储引擎特点 InnoDB 逻辑存储结构 MyISAM Memory 对比 存储引擎选择 索引 介绍 索引结构 BTree索引 Hash索引 索引分类 索引语法 SQL性能分析 SQL执行频率 慢查询日志 profile详情 expla…

CRC 循环冗余检测

目录 一、基础知识1.异或运算xor2.模2算术&#xff08;1&#xff09;模2加法和减法&#xff08;2&#xff09;模2乘法&#xff08;3&#xff09;模2除法 二、CRC循环冗余检测1.背景2.原理3.求R 一、基础知识 1.异或运算xor 异或&#xff0c;顾名思义&#xff0c;只有当两个数…

最新AI创作系统ChatGPT网站运营源码、支持GPT-4-Turbo模型,图片对话识图理解,支持DALL-E3文生图

一、AI创作系统 SparkAi是目前国内一款的ChatGPT对接OpenAI软件系统。那么如何搭建部署AI创作ChatGPT&#xff1f;小编这里写一个详细图文教程吧&#xff01;本系统使用NestjsVueTypescript框架技术&#xff0c;持续集成AI能力到本系统。支持OpenAI DALL-E3文生图&#xff0c;…

事件委派+自定义属性+编程式导航实现路由跳转及传参

当我们页面中有许多a标签需要实现点击跳转到同一个页面并携带不同的参数时&#xff0c;我们就可以使用事件委派自定义属性编程式导航 的方式&#xff0c;用最小的内存实现路由跳转的最大效率。 为什么我们不用router-link 进行跳转&#xff1f; 要知道&#xff0c;我们页面中…

【单调栈】子数组的最小值之和

import java.util.Deque; import java.util.LinkedList;/** 参考链接&#xff1a;https://leetcode.cn/problems/sum-of-subarray-minimums/solutions/1930857/gong-xian-fa-dan-diao-zhan-san-chong-shi-gxa5/* https://leetcode.cn/problems/sum-of-subarray-minim…

论文公式和代码对应

NGCF 论文地址 NGCF模型全部代码 import torch import torch.nn as nn import torch.nn.functional as F class NGCF(nn.Module):def __init__(self, n_user, n_item, norm_adj, args):super(NGCF, self).__init__()self.n_user n_userself.n_item n_itemself.device args…

数据结构与算法(Java)-树形DP题单

树形DP&#xff08;灵神笔记&#xff09; 543 二叉树的直径 543. 二叉树的直径 - 力扣&#xff08;LeetCode&#xff09; 给你一棵二叉树的根节点&#xff0c;返回该树的 直径 。 二叉树的 直径 是指树中任意两个节点之间最长路径的 长度 。这条路径可能经过也可能不经过根…