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

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

🌴专栏链接: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;  // 子进程pid
    int _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关闭不要的fd
            close(pipefd[1]);
            // 我们期望,所有的子进程读取“指令”的时候,都从标准输入读取

            // 1.3.1所以我们进行输入重定向
            dup2(pipefd[0], 0);

            // 1.3.2子进程开始等待获取命令
            WaitCommend();

            close(pipefd[0]);
            exit(0);
        }

        // 父进程
        // 1.3关闭不要的fd
        close(pipefd[0]);

        // 1.4将新的子进程和他的管道写端构建对象。
        end_points.push_back(EndPoint(id, pipefd[1]));

        fds.push_back(pipefd[1]);
    }
}

运行结果:

image-20231126224519572


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

在这里插入图片描述

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

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

相关文章

element 的 Notification 通知,自定义内容

通知事件&#xff1a; // 商户后台通知 MerchantBackgroundNotice() {// 禁止消息通知弹出多条if(this.notifyInstance) {this.notifyInstance.close();}const h this.$createElement; // 创建文本节点this.notifyInstance this.$notify({showClose: false, // 禁止关闭按钮…

Vue路由器(详细教程)

路由&#xff1a; 1.理解&#xff1a;一个路由(route)就是一组映射关系&#xff08;key-value)&#xff0c;多个路由需要路由器&#xff08;router&#xff09;进行管理。 2.前端路由&#xff1a;key是路径&#xff0c;value是组件。 1、先安装vue-router路由 npm i vue-route…

美女骑士开箱VELO Angel TT,银色天使,无痛骑行

阳光、女孩、自行车&#xff0c;脸上的笑容或明媚&#xff0c;或神秘&#xff0c;或青涩&#xff0c;在这个时候&#xff0c;世界上没有什么比骑行女孩更美的了&#xff01;      在北京&#xff0c;有一个热爱骑行的女孩&#xff0c;名叫季思铭&#xff0c;目前是中国农业…

电子学会C/C++编程等级考试2021年12月(二级)真题解析

C/C++等级考试(1~8级)全部真题・点这里 第1题:统计指定范围里的数 给定一个数的序列S,以及一个区间[L, R], 求序列中介于该区间的数的个数,即序列中大于等于L且小于等于R的数的个数。 时间限制:1000 内存限制:65536输入 第一行1个整数n、,分别表示序列的长。(0 < n…

NX二次开发UF_CURVE_ask_parameterization 函数介绍

文章作者&#xff1a;里海 来源网站&#xff1a;https://blog.csdn.net/WangPaiFeiXingYuan UF_CURVE_ask_parameterization Defined in: uf_curve.h int UF_CURVE_ask_parameterization(tag_t object, double param_range [ 2 ] , int * periodicity ) overview 概述 Retu…

回归预测 | MATLAB实现SMA+WOA+BOA-LSSVM基于黏菌算法+鲸鱼算法+蝴蝶算法优化LSSVM回归预测

回归预测 | MATLAB实现SMAWOABOA-LSSVM基于黏菌算法鲸鱼算法蝴蝶算法优化LSSVM回归预测 目录 回归预测 | MATLAB实现SMAWOABOA-LSSVM基于黏菌算法鲸鱼算法蝴蝶算法优化LSSVM回归预测效果一览基本介绍程序设计参考资料 效果一览 基本介绍 MATLAB实现SMAWOABOA-LSSVM基于黏菌算法…

基于ssm的网上订餐系统

一、系统架构 前端&#xff1a;jsp | js | css | jquery 后端&#xff1a;spring | springmvc | mybatis 环境&#xff1a;jdk1.7 | mysql | maven | tomcat 二、代码与数据库 三、功能介绍 01. web端-首页 02. web端-我的餐车 03. web端-我的订单 04. web端-用户中心 05. web…

每日一练2023.11.26——打印沙漏【PTA】

题目要求&#xff1a; 本题要求你写个程序把给定的符号打印成沙漏的形状。例如给定17个“*”&#xff0c;要求按下列格式打印 ************ *****所谓“沙漏形状”&#xff0c;是指每行输出奇数个符号&#xff1b;各行符号中心对齐&#xff1b;相邻两行符号数差2&#xff1b;…

条形码格式

条形码格式 简述EAN码EAN-13EAN-8 UPC码UPC-AUPC-E 简述 EAN码 EAN码&#xff08;European Article Number&#xff09;是国际物品编码协会制定的一种全球通用的商用条码。EAN码分为&#xff1a;标准版&#xff08;EAN-13&#xff09; 和 缩短版&#xff08;EAN-8&#xff09…

Linux4.5、进程状态

个人主页&#xff1a;Lei宝啊 愿所有美好如期而遇 目录 进程状态介绍 Linux下具体进程状态 R状态 和 S状态 D状态 T状态 t状态 Z状态 X状态 进程状态介绍 首先&#xff0c;进程状态有运行&#xff0c;阻塞&#xff0c;挂起&#xff0c;这些只是一个大体的概括&am…

排障不翻车 | 网络工程师必收藏的排障命令大全

网络工程师需要掌握多种网络故障排查手段&#xff0c; 以确保网络的稳定性和可用性。 以下是30个常用的排障命令 附带详细说明和一些用于华为网络设备的命令示例 以帮助小白网络工程师更好地理解&#xff1a; 1. Ping测试&#xff1a; • 方法&#xff1a;使用ping命令测试目…

Linux | Linux入门及常用基础命令介绍

关注CodingTechWork Linux Linux介绍 概述 Linux出现的时候是没有图像化界面&#xff0c;都是黑屏操作&#xff0c;靠命令来完成操作&#xff0c;如磁盘读写、网络管理等。企业级服务器的维护基本都通过跳板机ssh到对应的服务器上进行操作&#xff0c;一般无图形化界面。 远…

FreeRTOS学习之路,以STM32F103C8T6为实验MCU(2-8:事件标志组)

学习之路主要为FreeRTOS操作系统在STM32F103&#xff08;STM32F103C8T6&#xff09;上的运用&#xff0c;采用的是标准库编程的方式&#xff0c;使用的IDE为KEIL5。 注意&#xff01;&#xff01;&#xff01;本学习之路可以通过购买STM32最小系统板以及部分配件的方式进行学习…

Go 基本语法

一、​​​​变量定义方法 var 定义变量 var 变量名 类型 表达式 var name string "Snail" var age int 21 var isOK bool bool 2.类型推导方式定义变量 a 在函数内部&#xff0c;可以使用更简略的: 方式声明并初始化变量**注意&#xff1a;**短变量只能用于声…

计算机毕业设计|基于SpringBoot+MyBatis框架的电脑商城的设计与实现(商品和购物车)

计算机毕业设计|基于SpringBootMyBatis框架的电脑商城的设计与实现&#xff08;商品和购物车&#xff09; 商品热销排行 1 商品-创建数据表 1.使用use命令先选中store数据库。 USE store;2.在store数据库中创建t_product数据表。 CREATE TABLE t_product (id int(20) NOT …

Redis:持久化RDB和AOF

目录 概述RDB持久化流程指定备份文件的名称指定备份文件存放的目录触发RDB备份redis.conf 其他一些配置rdb的备份和恢复优缺点停止RDB AOF持久化流程AOF启动/修复/恢复AOF同步频率设置rewrite压缩原理触发机制重写流程no-appendfsync-on-rewrite 优缺点 如何选择 概述 Redis是…

Ubuntu+Tesla V100环境配置

系统基本信息 nvidia-smi’ nvidia-smi 470.182.03 driver version:470.182.03 cuda version: 11.4 查看系统体系结构 uname -aUTC 2023 x86_64 x86_64 x86_64 GNU/Linux 下载miniconda https://mirrors.tuna.tsinghua.edu.cn/anaconda/miniconda/?CM&OA https://mi…

新时代线下门店如何能够降低创业者的风险?

随着社会的发展和科技的进步&#xff0c;共享经济已经渗透到生活的各个领域。在这个大背景下&#xff0c;共享门店共享股东的商业模式应运而生&#xff0c;为传统门店经营带来了全新的思路和方向。而下面这个故事诠释了一个普通青年的底层崛起之路。 在繁华的都市中&#xff0c…

5、Qt:项目中包含多个子项目(.pro)/子模块(.pri)

一、说明&#xff1a; 在进行项目开发过程中&#xff0c;会涉及子项目/子模块的问题 Qt中使用TEMPLATE subdirs添加多个子项目&#xff1b;子项目可以单独编译生成可执行文件&#xff08;exe&#xff09;或者动态链接库&#xff08;dll&#xff09;等&#xff0c;供其他模块…

阿里云ACE认证之国际版与国内版对比!

大厂疯狂裁员&#xff0c;互联网行业迎来寒冬&#xff0c;技术人员被动陷入疯狂内卷。在愈加内卷的IT领域&#xff0c;“云计算”作为少有的蓝海&#xff0c;无疑是打工人未来实现职场提升、摆脱内卷的绝佳选择&#xff01; 对于云计算行业的人来说&#xff0c;最值得考的肯定是…