这里实现的进程池:一个父进程对多个子进程进行管道通信,大致如下
![](https://img-blog.csdnimg.cn/img_convert/1a2c5be0b2d7bc3b71d126893f32bdcf.png)
一、大致框架
知道需要创建几个子进程来进行通信
和这些子进程创建同数量的管道
实现子进程的数据接收
实现父进程的数据发送
结尾处理
注意要实现的是父进程对子进程的通信,发送数据的只有一个进程,而管道是通过fd文件描述符来实现通信的,所以我们需要记录每一个子进程对应的管道,以此来建立父进程对多个子进程之间的联系。(隐藏的意思就是我们只需要对子进程的对应的管道文件发送数据,就可基本实现通信了)
二、demo代码
以下代码,是根据所列的框架所写的,可以参考
int main()
{
vector<pair<pid_t, int>> slot;
// 创建子进程
for (int i = 0; i < PROCESS_NUM; ++i)
{
// 创建管道
int pipefd[2] = {0};
int n = pipe(pipefd);
assert(n != -1);
(void)n;
pid_t id = fork();
assert(id >= 0);
// 子进程
if (id == 0)
{
close(pipefd[1]);
// 判断数据合法性
while (true)
{
//接收数据
}
close(pipefd[0]);
exit(-1);
}
// 父进程
close(pipefd[0]);
slot.push_back({id, pipefd[1]});
}
// 注意要实现的是一个进程给多个进程发送数据,发送的代码得放在for外面
// 发送数据
srand((unsigned long)time);
while (true)
{
//发送数据
}
//关闭文件
for (const auto& slots : slot)
{
close(slots.second);
}
//等待子进程退出
for (const auto& slots : slot)
{
waitpid(slots.first, nullptr, 0);
}
return 0;
}
三、具体的接收和发送实现处理
#include <iostream>
#include <sys/types.h>
#include <sys/wait.h>
#include <vector>
#include <string>
#include <unistd.h>
#include <unordered_map>
#include <assert.h>
#include <stdlib.h>
#include "task.hpp"
using namespace std;
#define PROCESS_NUM 5
int waitComment(pid_t waitFd, bool &quit)
{
uint32_t command = 0;
ssize_t s = read(waitFd, &command, sizeof(command));//如果读到文件结尾会返回0(写到的文件关闭)
if (s == 0)
{
quit = true;
return -1;
}
assert(s == sizeof(uint32_t));
return command;
}
void SendData(pid_t who, int fd, int command)
{
write(fd, &command, sizeof(command));
cout << "[" << getpid() <<"] send a message:" << endl;
}
int main()
{
load();
vector<pair<pid_t, int>> slot;
// 创建子进程
for (int i = 0; i < PROCESS_NUM; ++i)
{
// 创建管道
int pipefd[2] = {0};
int n = pipe(pipefd);
assert(n != -1);
(void)n;
pid_t id = fork();
assert(id >= 0);
// 子进程
if (id == 0)
{
close(pipefd[1]);
// 判断数据合法性
while (true)
{
bool quit = false;
int comment = waitComment(pipefd[0], quit);
if (quit == true)
{
break;
}
if (comment >= 0 && comment < 5)
{
task[comment]();//只要是if(id == 0)中的代码块,都是由子进程来执行的
}
else
{
return -1;
}
}
close(pipefd[0]);
exit(-1);
}
// 父进程
close(pipefd[0]);
slot.push_back({id, pipefd[1]});
}
// 注意要实现的是一个进程给多个进程发送数据,发送的代码得放在for外面
// 发送数据
srand((unsigned long)time);
while (true)
{
int command = rand() % 4;
int choices = rand() % slot.size();
//关键点:给不同的子进程发送数据只需要对不同的fd发送数据即可 -- 访问控制
SendData(slot[choices].first, slot[choices].second, command);
sleep(1);
}
for (const auto& slots : slot)
{
close(slots.second);
}
for (const auto& slots : slot)
{
waitpid(slots.first, nullptr, 0);
}
return 0;
}
任务实现文件
#pragma once
#include <iostream>
#include <vector>
#include <string>
#include <unordered_map>
#include <functional>
using func = std::function<void()>; //C++11 标准 <返回值(参数类型)>
std::unordered_map<int, std::string> desc; //只是为了方便描述
std::vector<func> task;
void ReadSQL()
{
std::cout << "[" << getpid() << "]ReadSQL:数据库任务" << std::endl;
}
void Cal()
{
std::cout << "[" << getpid() << "]Cal:文件加密任务" << std::endl;
}
void Save()
{
std::cout << "[" << getpid() << "]Save:文件持久化任务" << std::endl;
}
void Exculeurl()
{
std::cout << "[" << getpid() << "]Exculeurl:url解析任务" << std::endl;
}
void load()
{
desc.insert({task.size(), "ReadSQL:数据库任务"});
task.push_back(ReadSQL);
desc.insert({task.size(), "Cal:文件加密任务"});
task.push_back(Cal);
desc.insert({task.size(), "Save:文件持久化任务" });
task.push_back(Save);
desc.insert({task.size(), "Exculeurl:url解析任务"});
task.push_back(Exculeurl);
}
void ShowHandler()
{
for (auto &e : desc)
{
std::cout << e.second << std::endl;
}
}
size_t HandlerSize()
{
return desc.size();
}
myProcessPool:myProcessPool.cpp
g++ -o $@ $^ -std=c++11
.PHONY:clean
clean:
rm -f myProcessPool