Linux——进程通信(二) 匿名管道的应用:进程池

本文介绍了如何通过进程池概念优化进程管理,通过预先创建并管理进程,当任务到来时快速分配执行,避免了频繁创建进程导致的时间浪费。文章详细描述了使用匿名管道进行进程间通信,并展示了如何实现进程池的创建、任务发布和子进程的退出机制。
摘要由CSDN通过智能技术生成

前言

之前我们学习了进程通过匿名管道进行通信,实现了两个进程的数据传输。

如果我们管理的是很多个进程,通过管道发送指令,因为如果管道中没有数据,读端必须等待,也就是被管理的进程们都在等待我发送的指令,那么我们可以通过特定的通讯方式,对进程实施控制,也就是让进程根据传输的指令去完成相应的操作。

一、进程池概念

我们知道,系统资源的获取是有成本的,比如我们创建进程,需要花一定的时间去完成,比如现在我们有一些比较重要的任务需要处理,如果等待任务到来,再创建进程去处理任务,时间上会慢一点,如果我们提前将进程创建好,任务到来,我们直接对进程分派任务,这样就能节省时间,这些提前创建好并被管理的进程,有任务来就分派执行,我们可以称之为进程池

打个比方,比如说你喝娃哈哈矿泉水,如果你感觉到口渴了,才去外面超市买娃哈哈矿泉水,这样成本是不是比较高,有点浪费时间,但是如果你提前在家里面放上一箱娃哈哈矿泉水,渴了就喝,顺手就拿的事情,效率就提高了,这也相当于把矿泉水进行池化了。

二、进程池实现

主要思路是先创建进程和信道,再发布任务,最后等待关闭父进程的写进程,让子进程read读到0,就退出子进程。最后父进程进行资源回收。

具体可以看代码注释,这里就不多BB了

ProcessPool.cpp

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

#define NUM 5

class channel
{
public:
    channel(string name, int fd, pid_t pid)
        : _name(name), _fd(fd), _pid(pid)
    {}

public:
    string _name;
    int _fd;
    pid_t _pid;
};

void Work()
{
    while (true)
    {
        int code = 0;
        ssize_t n = read(0, &code, sizeof(code));
        if (n == sizeof(code))
        {
            if (!init.Check(code))
            {
                cout << "任务码不合法,执行失败" << endl;
                continue;
            }
            init.RunTask(code);
        }
        else if (n == 0)
            break;
    }
}

void CreatProcess(vector<channel> &v)
{
    vector<int> vfd; // 存放父进程的写信道的fd
    for (int i = 0; i < NUM; i++)
    {
        // 创建管道
        int pipefd[2];
        int n = pipe(pipefd);
        assert(n == 0);

        // 创建进程
        pid_t id = fork();
        if (id < 0)
        {
            perror("fork");
            exit(1);
        }
        // 构建信道
        else if (id == 0)
        {
            // 子进程
            vfd.push_back(pipefd[1]);
            for (auto &fd : vfd) // 关闭子进程继承的写信道
            {
                close(fd);
            }
            dup2(pipefd[0], 0);
            Work();
            exit(0);
        }
        // 父进程
        close(pipefd[0]);
        v.push_back(channel(to_string(i + 1) + "号信道", pipefd[1], id));
    }
}

void PrintChannel(const vector<channel> &v)
{
    for (auto &c : v)
    {
        cout << c._name << "," << c._fd << "," << c._pid << endl;
    }
}

void SendTask(const vector<channel> &v, bool flag, int num = 1)
{
    int pos = 0;
    while (true)
    {
        int task = init.SelectTask(); // 选择任务
        pos %= v.size();              // 选择信道轮流执行任务
        channel c = v[pos++];

        cout<<"发送信息"<<init.ToDesc(task)<<"给"<<c._name<<",pid是"<<c._pid<<endl;

        write(c._fd, &task, sizeof(task)); // 发送任务

        if (!flag)
        {
            if (--num <= 0)
                break;
        }
        sleep(1);
    }
    sleep(1);
    cout << "发送任务完成" << endl;
}

void WaitPorcess(vector<channel> v)
{
    for (auto &c : v)
    {
        close(c._fd);
        pid_t rid = waitpid(c._fd, nullptr, 0);
        cout<<"等待子进程"<<c._pid<<"成功"<<endl;
    }
}

int main()
{
    vector<channel> channels;
    // 创建进程和信道
    CreatProcess(channels);
    // PrintChannel(channels);  //打印测试

    // 发送任务
    const bool always_loop = true;
    SendTask(channels, !always_loop, 10);

    // 进程等待回收
    WaitPorcess(channels);
    return 0;
}

Task.hpp

#pragma once

#include <iostream>
#include <functional>
#include <vector>
#include <ctime>

using namespace std;

typedef function<void()> task_t;

void Download()
{
    cout << "我正在下载,"
         << "pid:" << getpid() << endl;
}

void Print()
{
    cout << "我正在打印,"
         << "pid:" << getpid() << endl;
}

void PlayVideo()
{
    cout << "我正在播放,"
         << "pid:" << getpid() << endl;
}

class Init
{
public:
    Init()
    {
        tasks.push_back(Download);
        tasks.push_back(Print);
        tasks.push_back(PlayVideo);
        srand(time(nullptr));
    }

    void RunTask(int code)
    {
        tasks[code]();
    }

    string ToDesc(int code)
    {
        switch (code)
        {
        case 0:
            return "Download";
        case 1:
            return "Print";
        case 2:
            return "PlayVideo";
        default:
            return "Unkonw";
        }
    }

    bool Check(int code)
    {
        return code >= 0 && code < tasks.size();
    }

    int SelectTask()
    {
        return rand() % tasks.size();
    }

public:
    vector<task_t> tasks;
    // 任务码
    const int download_code = 0;
    const int print_code = 1;
    const int PlayVideo_code = 2;
};

Init init;

 运行结果如下。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值