Linux--进程池

文章描述了一个C++程序,其中父进程生成5个子进程并通过管道进行通信。每个子进程等待从父进程接收命令,并执行相应的任务,如数据库操作、URL解析等。父进程负责调度任务,用户可以选择显示任务列表或发送命令给特定子进程执行。read函数默认是阻塞的,而通过非阻塞模式或多线程可以实现异步读取。
摘要由CSDN通过智能技术生成

1.一个父进程生成五个子进程且分别建立与子进程管道

①用for循环,结束条件为<5 ②father父进程每次都要离开for循环,生成下一个子进程和管道

2.#include <cassert>和#include <assert.h>的区别

assert.h 是 C 标准库的头文件,cassert 是 C++ 标准库的头文件

3.子进程进行读取

那咱就关闭写端:close(pipefd[1]),保留读端

4.父进程进行写入

那咱就关闭读端:close(pipefd[0]),保留写端

5.让父进程实现:选择让哪个进程执行哪个命令

使用pair<pid_t,int>创建键值对,实现一一对应。

vector<pair<pid_t,int> > slots;创建各个进程与命令的对应表

slots.push_back(pair<pid_t,int>(id,pipefd[1]));将进程与命令建立连接

6.让子进程等待命令

waitCommand(pipefd[0]);//如果对方不发,我们就阻塞

int waitCommand(int waitFd)

{

    uint32_t command = 0;

    ssize_t s=read(waitFd,&command,sizeof(command));

    assert(s == sizeof(uint32_t));

    return command;

}

7.uint32_t对应几个字节

4个

8.默认情况下,read是XX等待?

在默认情况下,read函数是阻塞等待的。这意味着当调用read函数时,如果没有数据可读取,程序将一直等待直到有数据可用或者遇到了文件结束(EOF)。

当调用read函数时,它会阻塞程序的执行,直到满足以下条件之一:

  1. count字节的数据可用:如果读取的数据长度满足count字节,read函数会立即返回,并将数据复制到buf指向的缓冲区。
  2. 文件结束(EOF):如果文件已经读取到末尾,read函数将返回0,表示没有更多数据可读。
  3. 非阻塞IO(使用O_NONBLOCK选项):在某些情况下,可以将文件描述符设置为非阻塞模式,这样read函数将不会阻塞并立即返回,如果没有数据可读,则返回-1,并将errno设置为EAGAINEWOULDBLOCK

需要注意的是,对于套接字(网络套接字或UNIX域套接字)的阻塞read,当连接关闭时,read函数将返回0,表示没有更多数据可读。如果要使用非阻塞IO,需要在套接字上设置相应的选项。

如果需要实现非阻塞读取,可以使用O_NONBLOCK选项或fcntl函数来设置文件描述符的非阻塞模式,或者使用多线程/多进程的方式来实现异步读取。

9.typedef function<void()> func,以及它的等价写法

typedef function<void()> func表示定义函数对象,等价写法是using func=function<void()>

代码实现:

Makefile:

ProcessPool:ProcessPool.cc
	g++ -o $@ $^ -std=c++11 #-DDEBUG
.PHONY:clean
clean:
	rm -f ProcessPool

Task.hpp

#pragma once

#include <iostream>
#include <string>
#include <unistd.h>
#include <functional>
#include <vector>
#include <unordered_map>

using namespace std;
typedef function<void()> func;//等价于  using func=function<void()>

vector<func> callbacks;
unordered_map<int,string> desc;
void readMySQL()
{
    cout<<"process["<<getpid()<<"]执行访问数据库的任务" <<endl;
}

void execuleUrl()
{
    cout<<"process["<<getpid()<<"]执行url解析" <<endl;
}

void cal()
{
    cout<<"process["<<getpid()<<"]执行加密任务" <<endl;
}

void save()
{
    cout<<"process["<<getpid()<<"]执行数据持久化任务" <<endl;
}

void load()
{
    desc.insert({callbacks.size(),"readMySQL:读取数据库"});
    callbacks.push_back(readMySQL);

    desc.insert({callbacks.size(),"execuleUrl:进行url解析"});
    callbacks.push_back(execuleUrl);

    desc.insert({callbacks.size(),"cal:进行加密计算"});
    callbacks.push_back(cal);

    desc.insert({callbacks.size(),"save:进行数据的文件保存"});
    callbacks.push_back(save);

}

void showHandler()
{
    for(const auto &iter:desc)
    {
        cout<<iter.first<<"\t"<<iter.second<<endl;
    }
}

int handlerSize()
{
    return callbacks.size();
}

processPool.cc

#include <iostream>
#include <unistd.h>
#include <stdio.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <cassert>
#include <vector>
#include "Task.hpp"
#include <cstdlib>
#include <ctime>

#define PROCESS_NUM 5

using namespace std;

int waitCommand(int waitFd,bool &quit)
{
    uint32_t command = 0;
    ssize_t s = read(waitFd, &command, sizeof(command));
    if(s == 0)
    {
        quit=true;
        return -1;
    }
    assert(s == sizeof(uint32_t));
    return command;
}

void sendAndWakeup(pid_t who, int fd, uint32_t command)
{
    write(fd,&command,sizeof(command));
    cout<<"call process"<<who<<"execute"<<desc[command]<<"through"<<fd<<endl;
}

int main()
{
    load();
    // vector内放置pid:pipefd键值对
    vector<pair<pid_t, int>> slots;
    // 先创建多个进程
    for (int i = 0; i < PROCESS_NUM; i++)
    {
        // 创建管道
        int pipefd[2] = {0};
        int n = pipe(pipefd);
        assert(n > 0);
        (void)n;

        pid_t id = fork();
        assert(id != -1);
        // 子进程我们让它进行读取
        if (id == 0)
        {
            // 关闭写端
            close(pipefd[1]);
            // child
            while (true)
            {
                // pipefd[0]
                // 等命令
                bool quit=false;
                int command = waitCommand(pipefd[0],quit); // 如果对方不发,我们就阻塞
                if(quit) break;
                // 执行对应的命令
                if (command >= 0 && command < handlerSize())
                {
                    callbacks[command]();
                }
                else
                {
                    cout << "非法command:" << command << endl;
                }
            }
            exit(1);
        }
        // father,进行写入,关闭读端
        close(pipefd[0]);
        slots.push_back(pair<pid_t, int>(id, pipefd[1]));
    }
    // 父进程派发任务
    srand(unsigned long)time(nullptr)^getpid()^23323123123L);//让数据更随机
    while (true)
    {
        int select;
        int command;
        cout << "##############################################" << endl;
        cout << "#    1.show functions    2.send command      #" << endl;
        cout << "##############################################" << endl;
        cout << "Please Select>";
        cin >> select;
        if (select == 1)
            showHandler();
        else if (select == 2)
        {
            cout << "Enter Your Command>";
            // 选择任务
            cin >> command;
            // 选择进程
            int choice = rand() % slots.size();
            // 把任务给指定的进程
            sendAndWakeup(slots[choice].first, slots[choice].second, command);
        }
    }
    // 关闭fd,所有的子进程都会退出
    for(const auto& slot:slots)
    {
        close(slot.second);
    }

    //回收所有的子进程信息
    for(const auto & slot:slots)
    {
        waitpid(slot.first,nullptr,0);
    }

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值