【Linux】 进程池 一主多从 管道通信

目录

1.代码介绍

[2.channel 类](#2.channel 类)

3.进程池类编写

4.主函数及其他

[5. 源码](#5. 源码)


1.代码介绍

本文代码采用一主多从式(一个主进程(master)多个子进程(worker))通过管道进行通信,实现主进程分发任务,子进程完成任务,当主进程关闭管道时,子进程执行完任务后退出。

2.channel 类

创建一个channel类用于描述子进程,方便主进程与其通信。

成员变量:

int _wfd; //记录管道写描述符用于主进程发送数据

pid_t _pid; //子进程pid

string _name;

代码实现:

cpp 复制代码
class Channel
{
public:
	Channel(int wfd, pid_t pid, const string &name) : _wfd(wfd),
														   _pid(pid), _name(name) {}
	~Channel() {}
	int wfd() { return _wfd; }
	string name() { return _name; }
	pid_t pid() { return _pid; }
 	void Close() { close(_wfd); }//关闭写描述符,子进程读取完毕后会退出
private:
	int _wfd;
	pid_t _pid;
	string _name;
};

3.进程池类编写

该类用于管理子进程,具体功能:

1.创建子进程。

2.获取子进程(轮转方式保证负载均衡)。

3.主进程发送任务码给子进程。

4.进程等待。

5.控制进程退出。

代码实现:

cpp 复制代码
class ProcessPool
{
public:
	ProcessPool(int num) : _process_num(num) {}
	void createProcess(work_t work)
	{
		vector<int> fds;
		for (int i = 0; i < _process_num; ++i)
		{
			int pipefd[2]{0};
			pipe(pipefd);
			pid_t pid = fork();
			if (pid == 0)
			{
				if(!fds.empty())
				{
					for(auto& fd:fds)
					{
                        //关闭之前子进程管道的写端
						close(fd);
					}
				}
				close(pipefd[1]);
				dup2(pipefd[0], 0);
				work();
				exit(0);//子进程执行任务完毕会退出
			}

			close(pipefd[0]);
			string cname = "channel-" + to_string(i);
			_channels.push_back(Channel(pipefd[1], pid, cname));
			fds.push_back(pipefd[1]);
		}
	}
	int NextChannel()
	{
		static unsigned int index = 0;
		return (index++) % _process_num;
	}
	void SendTaskCode(int index, uint32_t code)
	{
		cout << "send code: " << code << " to " << _channels[index].name() << " sub prorcess id: " << _channels[index].pid() << endl;
		write(_channels[index].wfd(), &code, sizeof(code));
	}
	void Wait()
	{
		waitpid(-1, nullptr, 0);
	}
	void KillAll()
    {
        for (auto &channel : _channels)
        {
            channel.Close();
        }
    }
	~ProcessPool() {}

private:
	int _process_num;
	vector<Channel> _channels;
};

4.主函数及其他

主进程发送任务码,通过管道发送给子进程执行对应任务。

cpp 复制代码
void CtrlProcessPool(const shared_ptr<ProcessPool> &processpool_ptr, int cnt)
{
	while (cnt)
	{
		// a. 选择一个进程和通道
		int channel = processpool_ptr->NextChannel();
		// cout << channel.name() << endl;

		// b. 你要选择一个任务
		uint32_t code = NextTask();

		// c. 发送任务
		processpool_ptr->SendTaskCode(channel, code);

		sleep(1);
		cnt--;
	}
}
int main(int argc, char *argv[])
{
	if (argc != 2)
	{
		printf("\n\t usage ./processPool num\n");
		return 1;
	}
	int process_num = stoi(argv[1]);
	shared_ptr<ProcessPool> process_ptr = make_shared<ProcessPool>(process_num);
	process_ptr->createProcess(worker);
	CtrlProcessPool(process_ptr, 5);

	process_ptr->KillAll();
	process_ptr->Wait();
	return 0;
}

模拟任务:

cpp 复制代码
#pragma once

#include <iostream>
#include <unistd.h>
#include <functional>
using namespace std;

using work_t = function<void()>;
using task_t = function<void()>;

void PrintLog()
{
    cout << "printf log task" << endl;
}

void ReloadConf()
{
    cout << "reload conf task" << endl;
}

void ConnectMysql()
{
    cout << "connect mysql task" << endl;
}

task_t tasks[3] = {PrintLog, ReloadConf, ConnectMysql};

uint32_t NextTask()
{
    return rand() % 3;
}

void worker()
{
    // 从0中读取任务即可!
    while(true)
    {
        uint32_t command_code = 0;
        ssize_t n = read(0, &command_code, sizeof(command_code));
        if(n == sizeof(command_code))
        {
            if(command_code >= 3) continue;
            tasks[command_code]();
        }
        else if(n == 0) //管道写端关闭读端返回值位0
        {
            cout << "sub process: " << getpid() << " quit now..." << endl;
            break;
        }
    }
}

5. 源码

processPool.cc

cpp 复制代码
#include <iostream>
#include <string>
#include <cstdlib>
#include <vector>
#include <unistd.h>
#include <ctime>
#include <sys/wait.h>
#include <sys/types.h>
#include <memory>
#include "task.hpp"

using namespace std;
class Channel
{
public:
	Channel(int wfd, pid_t pid, const string &name) : _wfd(wfd),
														   _pid(pid), _name(name) {}
	~Channel() {}
	int wfd() { return _wfd; }
	string name() { return _name; }
	pid_t pid() { return _pid; }
 	void Close() { close(_wfd); }//关闭写描述符,子进程读取完毕后会退出
private:
	int _wfd;
	pid_t _pid;
	string _name;
};
class ProcessPool
{
public:
	ProcessPool(int num) : _process_num(num) {}
	void createProcess(work_t work)
	{
		vector<int> fds;
		for (int i = 0; i < _process_num; ++i)
		{
			int pipefd[2]{0};
			pipe(pipefd);
			pid_t pid = fork();
			if (pid == 0)
			{
				if(!fds.empty())
				{
					for(auto& fd:fds)
					{
						close(fd);
					}
				}
				close(pipefd[1]);
				dup2(pipefd[0], 0);
				work();
				exit(0);//子进程执行任务完毕会退出
			}

			close(pipefd[0]);
			string cname = "channel-" + to_string(i);
			_channels.push_back(Channel(pipefd[1], pid, cname));
			fds.push_back(pipefd[1]);
		}
	}
	int NextChannel()
	{
		static unsigned int index = 0;
		return (index++) % _process_num;
	}
	void SendTaskCode(int index, uint32_t code)
	{
		cout << "send code: " << code << " to " << _channels[index].name() << " sub prorcess id: " << _channels[index].pid() << endl;
		write(_channels[index].wfd(), &code, sizeof(code));
	}
	void Wait()
	{
		waitpid(-1, nullptr, 0);
	}
	void KillAll()
    {
        for (auto &channel : _channels)
        {
            channel.Close();
        }
    }
	~ProcessPool() {}

private:
	int _process_num;
	vector<Channel> _channels;
};

void CtrlProcessPool(const shared_ptr<ProcessPool> &processpool_ptr, int cnt)
{
	while (cnt)
	{
		// a. 选择一个进程和通道
		int channel = processpool_ptr->NextChannel();
		// cout << channel.name() << endl;

		// b. 你要选择一个任务
		uint32_t code = NextTask();

		// c. 发送任务
		processpool_ptr->SendTaskCode(channel, code);

		sleep(1);
		cnt--;
	}
}
int main(int argc, char *argv[])
{
	if (argc != 2)
	{
		printf("\n\t usage ./processPool num\n");
		return 1;
	}
	int process_num = stoi(argv[1]);
	shared_ptr<ProcessPool> process_ptr = make_shared<ProcessPool>(process_num);
	process_ptr->createProcess(worker);
	CtrlProcessPool(process_ptr, 5);

	process_ptr->KillAll();
	process_ptr->Wait();
	return 0;
}

task.hpp:

cpp 复制代码
#pragma once

#include <iostream>
#include <unistd.h>
#include <functional>
using namespace std;

using work_t = function<void()>;
using task_t = function<void()>;

void PrintLog()
{
    cout << "printf log task" << endl;
}

void ReloadConf()
{
    cout << "reload conf task" << endl;
}

void ConnectMysql()
{
    cout << "connect mysql task" << endl;
}

task_t tasks[3] = {PrintLog, ReloadConf, ConnectMysql};

uint32_t NextTask()
{
    return rand() % 3;
}

void worker()
{
    // 从0中读取任务即可!
    while(true)
    {
        uint32_t command_code = 0;
        ssize_t n = read(0, &command_code, sizeof(command_code));
        if(n == sizeof(command_code))
        {
            if(command_code >= 3) continue;
            tasks[command_code]();
        }
        else if(n == 0) //管道写端关闭读端返回值位0
        {
            cout << "sub process: " << getpid() << " quit now..." << endl;
            break;
        }
    }
}
相关推荐
涛ing8 分钟前
32. C 语言 安全函数( _s 尾缀)
linux·c语言·c++·vscode·算法·安全·vim
__雨夜星辰__10 分钟前
Linux 学习笔记__Day2
linux·服务器·笔记·学习·centos 7
大耳朵土土垚11 分钟前
【Linux】日志设计模式与实现
linux·运维·设计模式
学问小小谢13 分钟前
第26节课:内容安全策略(CSP)—构建安全网页的防御盾
运维·服务器·前端·网络·学习·安全
yaoxin5211231 小时前
第十二章 I 开头的术语
运维·服务器
ProgramHan1 小时前
1992-2025年中国计算机发展状况:服务器、电脑端与移动端的演进
运维·服务器·电脑
马立杰4 小时前
H3CNE-33-BGP
运维·网络·h3cne
云空5 小时前
《DeepSeek 网页/API 性能异常(DeepSeek Web/API Degraded Performance):网络安全日志》
运维·人工智能·web安全·网络安全·开源·网络攻击模型·安全威胁分析
深度Linux5 小时前
Linux网络编程中的零拷贝:提升性能的秘密武器
linux·linux内核·零拷贝技术
没有名字的小羊6 小时前
Cyber Security 101-Build Your Cyber Security Career-Security Principles(安全原则)
运维·网络·安全