当前位置: 首页 > news >正文

Linux:简易进程池编写

  • 设计概念
  • Channel
  • 初始化
  • 创建任务
  • 子进程工作
  • 轮询方案
  • 分配工作
  • 关闭子进程和管道
  • Main

设计概念

进程池,即我们可以预先创建一堆子进程和对应的管道。等父进程有任务时派发给子进程工作。这样就可以节省开辟进程的花销:

当没有任务时,即管道为空。那么子进程就是阻塞状态不会影响其他进程工作效率。

但是注意我们要将任务均衡地派发给子进程,即实现负载均衡

Channel

首先我们要设计一个方案让父进程能统一管理与子进程之间的管道,最好的方法就是封装一个类。
那么类的成员变量必然要有管道的写端fd、子进程的pid还可以有给子进程的编号。

classChannel{public:Channel(intwfd,pid_t id,conststd::string&name):_wfd(wfd),_subprocessid(id),_name(name){}intGetWfd(){return_wfd;}pid_tGetPidProcessId(){return_subprocessid;}std::stringGetName(){return_name;}//关闭写端voidColseChannel(){close(_wfd);}//等待子进程voidWait(){pid_t rid=waitpid(_subprocessid,nullptr,0);if(rid>0){std::cout<<"wait"<<rid<<"success!"<<std::endl;}}~Channel(){}private:int_wfd;pid_t _subprocessid;std::string _name;};

初始化

接下来我们要初始化Channel数组。
根据要创建的worker个数num,我们可以写一个简单的for循环创建管道和子进程。由子进程关闭写端,父进程关闭读端,即可。
但是我们要注意一个细节,这里以创建两个子进程举例,这里先创建第一个worker:

然后分别关闭读写端:

此时我们创建第二个worker:

然后分别关闭读写端:

这时我们发现第二个子进程对第一个管道的写端并没有关闭,此时有可能造成父进程最后无法结束进程。
因此我们在创建新的worker时,要将前面的worker的写端关闭:

voidCreatChannelAndSub(intnum,std::vector<Channel>*channels,task_t task){for(inti=0;i<num;i++){intpipefd[2]={0};intn=pipe(pipefd);//创建管道失败if(n<0)exit(1);//创建子进程pid_t id=fork();if(id==0){//非空就要关闭前面的写端if(!channels->empty()){for(auto&channel:*channels)channel.ColseChannel();}close(pipefd[1]);//重定向到标准输入dup2(pipefd[0],0);//回调函数task();close(pipefd[0]);exit(0);}//父进程std::string channel_name="Channel-"+std::to_string(i);close(pipefd[0]);channels->emplace_back(pipefd[1],id,channel_name);}}

创建任务

我们来实现不同的任务以分配给子进程,首先重命名下函数指针用以实现回调函数:

随意实现三个简单的任务:

voidPrint(){std::cout<<"I am print task"<<std::endl;}voidDownLoad(){std::cout<<"I am download task"<<std::endl;}voidFlush(){std::cout<<"I am flush task"<<std::endl;}

创建回调表:

分配任务:

intSelectTask(){returnrand()%TaskNum;}

执行任务:

voidExcuteTask(intnumber){if(number<0||number>2)return;tasks[number];}

子进程工作

以及有了上面的一系列任务,我们是时候给子进程工作了:

voidwork(){while(true){intcommand=0;intn=read(0,&command,sizeof(command));if(n==sizeof(int)){std::cout<<"pid is:"<<getpid()<<"handler task"<<std::endl;ExcuteTask(command);}//写端关闭if(n==0){std::cout<<"sub process:"<<getpid()<<" quit"<<std::endl;break;}}}

轮询方案

前面提到我们要实现负载均衡,这里可以简单实现为轮询。即轮流给子进程派送任务:

intNextChannel(intchannelnum){staticintnext=0;intchannel=next;next++;next%=channelnum;returnnext;}

分配工作

子进程的工作也有了,轮询方案也有了,就可以给子进程正是分配工作了:

voidSendTaskCommand(Channel&channel,inttaskcommand){write(channel.GetWfd(),&taskcommand,sizeof(int));}voidctrlProcessOnce(std::vector<Channel>&channels){sleep(1);//挑选任务inttaskcommand=SelectTask();//挑选信道和进程intchannel_index=NextChannel(channels.size());//发送任务SendTaskCommand(channels[channel_index],taskcommand);std::cout<<std::endl;std::cout<<"taskcommand:"<<taskcommand<<"channel:"<<channels[channel_index].GetName()\<<"sub process:"<<channels[channel_index].GetPidProcessId()<<std::endl;}voidctrlProcess(std::vector<Channel>&channels,inttimes=-1){if(times>0){while(times--)ctrlProcessOnce(channels);}else{while(true)ctrlProcessOnce(channels);}}

关闭子进程和管道

有了前面关闭子进程所有写端的处理,我们能直接关闭子进程的读端进而使子进程退出,对子进程等待即可:

voidCleanUpChannel(std::vector<Channel>&channels){for(auto&channel:channels){channel.ColseChannel();channel.Wait();}}

Main

接下来就是在main函数里安排代码执行的顺序,我们还可以通过选项的形式控制生成的子进程数量:

intmain(intargc,char*argv[]){if(argc!=2){std::cerr<<"Usage:"<<argv[0]<<" processnum"<<std::endl;}intnum=std::stoi(argv[1]);std::vector<Channel>channels;//1.创建子进程和信道CreatChannelAndSub(num,&channels,work);//2.控制子进程ctrlProcess(channels,5);//3.回收资源CleanUpChannel(channels);return0;}

来尝试运行代码:

完整代码

http://www.jsqmd.com/news/74234/

相关文章:

  • 英雄联盟智能助手League Akari:重新定义游戏体验的完整指南
  • 前端技术的下一次跃迁:从工程化到智能化的全面演进
  • UE5 材质-23:材质里参数的分组与排序。材质参数集,为了批量修改很多个材质实例里的参数的值。
  • 【孙子兵法之下篇】012. 孙子兵法·火攻篇
  • Wan2.2-T2V-A14B如何应对‘先因后果’的时间逻辑关系?
  • Wan2.2-T2V-A14B模型更新日志解读:v2.2版本带来了什么?
  • Wan2.2-T2V-A14B生成未来城市概念视频的艺术表现力
  • 正则表达式
  • 告别AI失忆症!Mem0+Milvus打造AI长期记忆,小白也能快速上手!
  • 利用cubemx和HAL库重写江科协的oled驱动程序
  • Wan2.2-T2V-A14B如何实现多角色协同行为的合理编排
  • 第八章: 滤波模块 —— 给你的数据“洗个澡”!
  • 十一.递归初阶
  • Wan2.2-T2V-A14B在航空航天科普视频中的应用前景
  • DownKyi终极指南:快速掌握B站视频下载全技巧
  • 突破数学推理瓶颈:DeepSeek-Prover-V1.5开创形式化反馈训练新范式
  • 每日学习python(十)
  • GLM-4.5系列开源模型发布:重新定义智能体基座的技术边界与商业价值
  • Wan2.2-T2V-A14B模型在视频广告A/B测试中的快速迭代优势
  • 代码智能新纪元:Qwen3-Coder国产大模型技术架构与开发实战全攻略
  • Day 28 函数的定义与参数
  • Wan2.2-T2V-A14B生成金融财经图表动态演示视频的案例
  • 高分辨率视频生成难题破解:Wan2.2-T2V-A14B实测报告
  • DevUI modal 弹窗表单联动实战:表格编辑功能完整实现
  • 模板生成能力终极对决:ERNIE-4.5与DeepSeek技术深度测评报告
  • 深度学习中 z-score 标准化理解
  • 9 个专科生课堂汇报工具推荐,AI 写作降重神器
  • 别再乱装工具了!7 款最佳渗透测试工具(超详细),收藏这篇就够了
  • 救命!网安技能不用瞎找了:渗透 / 运维 / 应用安全详细图谱 + 工具包
  • 深度解析HiPO:大语言模型动态推理的革命性突破——从AutoThink范式到混合策略优化的技术演进