LIUNX系统编程:进程池的实现

1.什么是进程池

每一个可执行程序,在被执行前都要转化为进程,操作系统都要为其创建PCB,地址空间,页表,构建映射关系,进程池就是创建进程时,创建很多个进程,如果要执行程序,就直接使用创建好的进程。就像一次性创建5个进程,肯定是比一次创建一个创建5次的效率更好的,将任务均匀的分配给进程执行。

2.进程池原理

采用面相对象的方法对进程管理根据需求抽离出进程的主要特征,将其组织起来就是进程池。

首先fork创建多个子进程。

对进程进行控制,通过父进程向管道中写入任务码,子进程读取任务码后,执行对应的任务。

对进程进行回收。

3.进程池的实现

创建进程池有一个隐藏非常深的bug,一个管道拥有多个写端,导致进程无法正常退出。

这里的退出方式,关闭管道的写端,读端就会读到文件末尾,进而退出进程。

主要的原因就是,子进程是父进程身上扒下来的,文件描述符表和父进程是一样的。

创建第一个进程的时候,将父进程读端关闭,子进程写端关闭。

我们在创建第二进程的时候,会把父进程文件描述表中的4,也给拷贝过来,这样另一个子进程也会指向管道的写端。

这样我们不想写入任务码了,关闭父进程的写端,但是还后其他的文件描述符在指向,这样就不会读到文件的末尾,就无法将进程退出。

我么可以采用两种方式解决这种问题。

1.从后向前关闭父进程的写端,因为最后创建的进程的管道,只有父进程指向写端,最后一个进程退出了,指向倒数第二个管道的写端的fd也就关闭了,依次就可正常退出了

2.讲每个进程的wfd存到vector中,fork之后将vctotr的wfd全部关闭,最后关闭完将该进程的写端fd存入vector中。

processpool.cpp

#include <iostream>
#include <vector>
#include <string>
#include <cstdlib>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include "task.hpp"
using namespace std;

enum//设置错误类型
{
    useageError = 1,//使用错误
    pipeError,
    forkError
};

class channal
{
public:
    channal(int wfd, string name, pid_t pid)
        : _wfd(wfd), _name(name), _pid(pid)
    {
    }
    
    int wfd()//返回该进程写端管道的fd
    {
        return _wfd;
    }
    
    string name()//返回该进程的名字
    {
        return _name;
    }

    pid_t pid()//返回该进程的pid
    {
        return _pid;
    }
    void Close()//关闭进程
    {
        close(_wfd);
    }
private:

    int _wfd;
    string _name;
    pid_t _pid;
};

class processpool
{
public:
    processpool(int sum)
        : _channalssum(sum)
    {
    }

    void create(work_t work/*回调函数*/)//创建进程
    {
        vector<int> wfds;
        int i = 0;
        while (i < _channalssum)
        {
            int pipfd[2] = {0};
            int ret = pipe(pipfd);
            // children read
            if (ret == -1)
            {
                exit(pipeError);
            }

            pid_t id = fork();

            if (id == -1)
            {
                exit(forkError);
            }

            // 子进程工作
            if (id == 0)
            {
                if(!wfds.empty())
                {
                    for(auto a:wfds)
                    {
                        close(a);
                    }
                }
                // read
                close(pipfd[1]);
                dup2(pipfd[0], 0);
                work();
                exit(0);
            }
            //父进程
            close(pipfd[0]);
            string cname = "childprocess" + to_string(i);
            channals.push_back(channal(pipfd[1],cname,id));
            wfds.push_back(pipfd[1]);
            i++;   
        }
    }

    int nextchannal()//选择管道
    {
        static int cnt = 0;
        cnt++;
        cnt %= channals.size();
        return cnt;
    }

    void sendCode(int index ,uint32_t code)//发送任务
    {
        cout << "send code: " << code << " to " << channals[index].name() << " sub prorcess id: " <<  channals[index].pid() << endl;
        write(channals[index].wfd(),&code,sizeof(code));
        sleep(1);
    }

    //关闭所有写端
    void killall()
    {
        for(auto &ch : channals)
        {
            ch.Close();
            pid_t rid = waitpid(ch.pid(),nullptr,0);
            if(rid == ch.pid())
            {
                cout<<"wait sucess pid:"<< ch.pid()<<endl;
            }
        }
    }

private:
    vector<channal> channals;
    int _channalssum;
};


void ctrlProcess(processpool &prp)
{
    int cnt = 5;
    while(cnt)
    {
        //选择渠道
        int index = prp.nextchannal();
        //选择任务
        uint32_t code = sendWork();
        //发送任务
        prp.sendCode(index,code);
        sleep(1);
        cnt--;
    }
}

int main(int argc, char *argv[])
{
    if (argc != 2)//参数不是 2个
    {
        cout << "uesageError" << endl;
        return useageError;
    }
    int sum = stoi(argv[1]);
    // 创建进程
    if (sum <= 0)
    {
        cout << "process sum must > 0" << endl;
        return forkError;
    }
    processpool prp(sum);
    prp.create(worker);

    //控制进程
    ctrlProcess(prp);
    //回收资源
    prp.killall();
    return 0;
}

task.hpp

#pragma once
using namespace std;

typedef void (*work_t)();//函数指针类型
typedef void (*task_t)();

void printlog()
{
    cout << "working printlog" << endl;
}

void linkMYSQL()
{
    cout << "working linkMYSQL" << endl;
}

void download()
{
    cout << "working downloade" << endl;
}

task_t _task[3] = {printlog, linkMYSQL, download};

int sendWork()
{
    int ret = rand() % 3;
    return ret;
}

void worker()
{
    //int cnt = 5;
    while (1)
    {
        uint32_t code = 0;
        size_t n = read(0, &code, sizeof(code));//从管道中读任务
        if (n == sizeof(code))
            _task[code]();
        else if(n == 0)//说明写端关闭了,读到文件的末尾了
        {
            cout<<"wfd closed quite now"<<endl;
            break;
        }
        cout << "i am working" << endl;
        sleep(1);
    }
}

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

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

相关文章

HTML_CSS学习:背景、鼠标相关属性

一、背景相关属性 相关代码&#xff1a; <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>背景相关属性</title><style>body{background-color: greenyellow;}div{width: 400px;height: …

C语言-分支和循环语句、函数、数组、操作符、指针、结构体

目录 一、scanf和getchar二、产生随机数函数三、辗转相除法求最大公约数四、函数的参数4.1 实际参数&#xff08;实参&#xff09;4.2 形式参数&#xff08;形参&#xff09;4.3 内存分配 五、函数的调用5.1 传值调用5.1 传址调用 六、函数的声明和定义6.1 函数的声明6.2 函数的…

Day62:单调栈 LeedCode503. 下一个更大元素 II 42. 接雨水

503. 下一个更大元素 II 给定一个循环数组 nums &#xff08; nums[nums.length - 1] 的下一个元素是 nums[0] &#xff09;&#xff0c;返回 nums 中每个元素的 下一个更大元素 。 数字 x 的 下一个更大的元素 是按数组遍历顺序&#xff0c;这个数字之后的第一个比它更大的数…

服务运维问题

2024-05-01&#xff08;docker 部署的 jar包自动关闭&#xff09; 查询运行情况&#xff1a;处于退出状态 docker ps -a 查询日志&#xff1a;看不出问题 docker logs -f --tail1000 demo-java 查询关于java服务日志&#xff1a;Out of memory: Kill process 16236 (java) …

智能BI产品设计

BI概念 目录 BI概念 一&#xff1a;与BI相关的几个重要概念 二&#xff1a;数据仓库 VS 数据库 BI架构 一&#xff1a;数据分析通用流程 二&#xff1a;BI平台基本架构 可视化图形 一&#xff1a;如何选择可视化图形 二&#xff1a;数据展示形式 三&#xff1a;数据…

ComfyUI 基础教程(十三):ComfyUI-Impact-Pack 面部修复

SD的WebUI 中的面部修复神器 ADetailer,无法在ComfyUI 中使用。那么如何在ComfyUI中进行面部处理呢?ComfyUI 中也有几个面部修复功能,比如ComfyUI Impact Pack(FaceDetailer),以及换脸插件Reactor和IPAdapter。 ComfyUI-Impact-Pack 是一个功能强大的插件,专为 ComfyUI …

GiantPandaCV | FasterTransformer Decoding 源码分析(三)-LayerNorm介绍

本文来源公众号“GiantPandaCV”&#xff0c;仅用于学术分享&#xff0c;侵权删&#xff0c;干货满满。 原文链接&#xff1a;FasterTransformer Decoding 源码分析(三)-LayerNorm介绍 作者丨进击的Killua 来源丨https://zhuanlan.zhihu.com/p/669440844 编辑丨GiantPandaC…

LLVM的ThinLTO编译优化技术在Postgresql中的应用

部分内容引用&#xff1a;https://blog.llvm.org/2016/06/thinlto-scalable-and-incremental-lto.html LTO是什么&#xff1f; 链接时优化&#xff08;Link-time optimization&#xff0c;简称LTO&#xff09;是编译器在链接时对程序进行的一种优化。它适用于以文件为单位编译…

考研数学|基础跟张宇,强化直接1000题还是先做660?

跟宇哥用1000题的&#xff0c;我愿称之为卷王之王&#xff01;660对基础阶段是绝佳的查漏补缺&#xff0c;必做&#xff01; 自我介绍一下&#xff1a;我21年一战数学83&#xff0c;总分没过线&#xff0c;22年二战143&#xff0c;逆袭上岸211&#xff01;660是我的心头好&…

奶爸预备 |《伯克毕生发展心理学.从0岁到青少年》 / (美) 劳拉·E. 伯克著——读书笔记

目录 引出第一篇 人的发展理论与研究第1章 历史、理论和研究方法 第二篇 发展的基础第2章 生物基础与环境基础第3章 孕期发育、分娩及新生儿 第三篇 婴儿期和学步期&#xff1a;0~2岁第4章 婴儿期和学步期的身体发育第5章 婴儿期和学步期的认知发展第6章 婴儿期和学步期的情绪与…

华为OD机试【垃圾信息拦截】(java)(100分)

1、题目描述 大众对垃圾短信深恶痛绝&#xff0c;希望能对垃圾短信发送者进行识别&#xff0c;为此&#xff0c;很多软件增加 了垃圾短信识别机制。经分析&#xff0c;发现正常用户的短信通常具备交互性&#xff0c;而垃圾短信往 往都是大量单向的短信&#xff0c;按照如下规则…

vue3中标签的ref属性

组合API-ref属性 在vue2.x中&#xff0c;可以通过给元素添加refxxx属性&#xff0c;然后在代码中通过this.$refs.xxx获取到对应的元素 然而在vue3中时没有$refs这个东西的&#xff0c;因此vue3中通过ref属性获取元素就不能按照vue2的方式来获取。 目标&#xff1a;掌握使用re…

Python项目实战,用Python实现2048游戏

目录 写在前言项目介绍项目思路环境搭建项目实现初始化Python类初始化游戏窗口定义游戏棋盘和方块移动和合并游戏主循环 进一步探索 写在前言 hello&#xff0c;大家好&#xff0c;我是一点&#xff0c;专注于Python编程&#xff0c;如果你也对感Python感兴趣&#xff0c;欢迎…

基于JSP的酒店客房管理系统(三)

目录 第四章 系统各模块的实现 4.1客房管理系统首页的实现 4.1.1 客房管理系统首页概述 4.2客房管理系统前台的实现 4.2.1 客房管理系统前台概述 4.2.2 客房管理系统前台实现过程 4.2.3 预定客房信息及客房信息的查询 4.3客房管理系统后台的实现 4.3.1 客房管理系统后…

搜索算法系列之四(斐波那契)

以下算法被验证过&#xff0c;如有什么问题或有补充的欢迎留言。 前言 斐波那契数列&#xff0c;又称黄金分割数列&#xff0c;是由意大利数学家&#xff08;Leonardo Fibonacci&#xff09;在1202年提出的。这个数列的递推关系是F(0)1&#xff0c;F(1)1&#xff0c;F(n)F(n-…

最近惊爆谷歌裁员

Python团队还没解散完&#xff0c;谷歌又对Flutter、Dart动手了。 什么原因呢&#xff0c;猜测啊。 谷歌裁员Python的具体原因可能是因为公司在进行技术栈的调整和优化。Python作为一种脚本语言&#xff0c;在某些情况下可能无法提供足够的性能或者扩展性&#xff0c;尤其是在…

【6D位姿估计】数据集汇总 BOP

前言 BOP是6D位姿估计基准&#xff0c;汇总整理了多个数据集&#xff0c;还举行挑战赛&#xff0c;相关报告被CVPR2024接受和认可。 它提供3D物体模型和RGB-D图像&#xff0c;其中标注信息包括6D位姿、2D边界框和2D蒙版等。 包含数据集&#xff1a;LM 、LM-O 、T-LESS 、IT…

android系统serviceManger源码解析

一&#xff0c;serviceManger时序图 本文涉及到的源码文件&#xff1a; /frameworks/native/cmds/servicemanager/main.cpp /frameworks/native/libs/binder/ProcessState.cpp /frameworks/native/cmds/servicemanager/ServiceManager.cpp /frameworks/native/libs/binder/IP…

练习题(2024/5/6)

1路径总和 II 给你二叉树的根节点 root 和一个整数目标和 targetSum &#xff0c;找出所有 从根节点到叶子节点 路径总和等于给定目标和的路径。 叶子节点 是指没有子节点的节点。 示例 1&#xff1a; 输入&#xff1a;root [5,4,8,11,null,13,4,7,2,null,null,5,1], target…

【数据结构】C++语言实现栈(详细解读)

c语言中的小小白-CSDN博客c语言中的小小白关注算法,c,c语言,贪心算法,链表,mysql,动态规划,后端,线性回归,数据结构,排序算法领域.https://blog.csdn.net/bhbcdxb123?spm1001.2014.3001.5343 给大家分享一句我很喜欢我话&#xff1a; 知不足而奋进&#xff0c;望远山而前行&am…