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

news2025/2/23 3:25:15

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

🌴专栏链接: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


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

在这里插入图片描述

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

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

相关文章

Unity - Graphic解析

Gpahic 的作用 Graphic 是 Unity最基础的图形基类。主要负责UGUI的显示部分。 由上图可以看你出我们经常使用的Image&#xff0c;Text&#xff0c;都是继承自Graphic。 Graphic的渲染流程 在Graphic的源码中有以下属性 [NonSerialized] private CanvasRenderer m_CanvasRend…

【Python游戏开发】使用Python编写拼图益智游戏教程

使用Python编写拼图益智游戏 大家一般都玩过拼图益智游戏&#xff0c;或者类似的游戏。今天&#xff0c;就给大家使用pygame库在Python中构建一个拼图益智小游戏。这个拼图小游戏是构建一个围绕着将1-15个数字排列在16个方块的网格中的游戏。 现在&#xff0c;让我们从今天的惊…

【数据中台】开源项目(2)-Dbus数据总线

1 背景 企业中大量业务数据保存在各个业务系统数据库中&#xff0c;过去通常的同步数据的方法有很多种&#xff0c;比如&#xff1a; 各个数据使用方在业务低峰期各种抽取所需数据&#xff08;缺点是存在重复抽取而且数据不一致&#xff09; 由统一的数仓平台通过sqoop到各个…

那些年,关于CKACKS认证的那些事儿?

前言 遥想2020年的年初&#xff0c;疫情封城封村之际&#xff0c;工作之余在B站将尚硅谷的linux中的k8s视频完整系统的学习了一遍&#xff0c;自此像是打通了任督二脉一般&#xff0c;开启了对k8s的探索之旅&#xff0c;一路也是磕磕绊绊的在工作中使用k8s。 终于在23年的6月仲…

Rust在Web开发中的应用

欢迎关注我的公众号lincyang新自媒体&#xff0c;回复关键字【程序员经典书单】&#xff0c;领取程序员的100本经典书单 大家好&#xff01;我是lincyang。 今天我们将一起深入探索Rust在Web开发领域的应用。尽管Rust最初设计用于系统编程&#xff0c;但其性能、安全性和现代并…

CANdelaStudio 使用教程5 编辑DID

文章目录 在哪编辑DID的分类编辑快照数据添加 DID 在哪编辑 DID的分类 编辑快照数据 添加 DID

带你用uniapp从零开发一个仿小米商场_9. 轮播图组件封装及使用

导航栏有了,接下来就是轮播图了,轮播图如下, 因为uniapp 官方自己有轮播图,所以这里就不自己写了,直接使用uniapp的轮播图二次开发就好 uniapp的轮播图组件叫swiper ,感兴趣的朋友可以点击链接,直接去看官方文档,也可以看我这里实操 用hbuilderX编译uniapp的代码有一个好处…

redis实现消息延迟队列

业务场景 在很多软件系统功能中都会出现定时任务的业务场景,比如提前点单,比如定时发布动态,文章等而出现这样的的定时的任务为延迟队任务 代码模块 任务的持久化一般都需要建立一个任务表和任务日志表,避免宕机导致任务失效,先新建立一个数据库,创建基本的任务表和任务日志表…

uniapp+vue基于Android的校园二手跳蚤市场的设计与实现 微信小程序

实现功能&#xff1a; 用户管理&#xff1a;登陆、注册、注销、修改密码、上传头像、修改资料 发布与检索&#xff1a;发布商品、模糊搜索、人气排序、价格排序、时间排序、推送商品&#xff08;协同过滤算法实现个性化推荐&#xff09;&#xff0c;最新发布、分类检索 核心交易…

Less 嵌套规则

文章目录 前言描述style.less输出后言 前言 hello world欢迎来到前端的新世界 &#x1f61c;当前文章系列专栏&#xff1a;Sass和Less &#x1f431;‍&#x1f453;博主在前端领域还有很多知识和技术需要掌握&#xff0c;正在不断努力填补技术短板。(如果出现错误&#xff0c;…

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

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

案例027:基于微信小程序的校园二手平台的设计与实现

文末获取源码 开发语言&#xff1a;Java 框架&#xff1a;SSM JDK版本&#xff1a;JDK1.8 数据库&#xff1a;mysql 5.7 开发软件&#xff1a;eclipse/myeclipse/idea Maven包&#xff1a;Maven3.5.4 小程序框架&#xff1a;uniapp 小程序开发软件&#xff1a;HBuilder X 小程序…

【漏洞复现】熊海cms 存在sql注入 附poc

漏洞描述 熊海CMS 是由熊海开发的一款可广泛应用于个人博客,个人网站,企业网站的一套网站综合管理系统。 其采用前后端整合设计思路,php,Apache,mysql,前端使用Bootstrap和少许jquery前端框架开发; 网站样式设计简洁大方,整体功能点并不多,但功能正好够用;拥有一个…

AI辅助工具

任务拆解工具 Magic ToDo - GoblinTools 可用的AI搜索和对话工具&#xff1a;chatgpt 梦畅AI

打开CMD的六种方法,CMD快捷键,CMD命令大全及详解

目录 前言1. winR快捷键2、通过文本文档创建&#xff1b;3、通过C盘中的cmd.exe文件打开&#xff1b;4、创建快捷方式&#xff1b;5、通过PowerShell打开&#xff1b;6、通过文件夹导航栏打开&#xff1b; 前言 自己的电脑win键失灵了&#xff0c;想通过winR来调出cmd&#xff…

【聚类 | K-means】原理及推导流程(附模板代码,库手撕实现)

&#x1f935;‍♂️ 个人主页: AI_magician &#x1f4e1;主页地址&#xff1a; 作者简介&#xff1a;CSDN内容合伙人&#xff0c;全栈领域优质创作者。 &#x1f468;‍&#x1f4bb;景愿&#xff1a;旨在于能和更多的热爱计算机的伙伴一起成长&#xff01;&#xff01;&…

代码随想录算法训练营第四十八天|121. 买卖股票的最佳时机、122. 买卖股票的最佳时机 II

LeetCode 121. 买卖股票的最佳时机 题目链接&#xff1a;121. 买卖股票的最佳时机 - 力扣&#xff08;LeetCode&#xff09; 直觉告诉我要贪心算法&#xff0c;章节告诉我得用DP来做&#xff0c;行&#xff0c;都做一下&#xff01; 贪心&#xff1a;只能买一次&#xff0c;所…

找不到vcomp120.dll该如何修复?vcomp120.dll丢失的5个可行解决方法

本文将对vcomp120.dll文件的丢失原因进行详细分析&#xff0c;并提供五个有效的修复方法。同时&#xff0c;本文还将深入介绍vcomp120.dll文件的作用及其在程序运行中的重要性。 一、vcomp120.dll文件丢失原因 操作系统损坏&#xff1a;由于病毒感染、系统错误等原因&#xf…

【Spring】Spring事务详解

&#x1f4eb;作者简介&#xff1a;小明java问道之路&#xff0c;2022年度博客之星全国TOP3&#xff0c;专注于后端、中间件、计算机底层、架构设计演进与稳定性建设优化&#xff0c;文章内容兼具广度、深度、大厂技术方案&#xff0c;对待技术喜欢推理加验证&#xff0c;就职于…

ChatGPT化身“AI间谍”:你在网上说的每句话都将被监控

大多数人使用 ChatGPT 就是用来聊天或者辅助学习、办公。 然而现在一些“间谍软件”公司正在探索如何使用ChatGPT和其他新兴的AI来监视社交媒体上的用户。 其中一家由俄罗斯企业家创立的Social Links的公司正使用 ChatGPT 作为助手&#xff0c;监控着用户在Facebook、Instagr…