大丰做网站建设的公司,电子商务的网站有哪些,苏州网站建设有限公司,给网站做解答是干嘛的设计概念Channel初始化创建任务子进程工作轮询方案分配工作关闭子进程和管道Main设计概念
进程池#xff0c;即我们可以预先创建一堆子进程和对应的管道。等父进程有任务时派发给子进程工作。这样就可以节省开辟进程的花销#xff1a;
当没有任务时#xff0c;即管道为空…设计概念Channel初始化创建任务子进程工作轮询方案分配工作关闭子进程和管道Main设计概念进程池即我们可以预先创建一堆子进程和对应的管道。等父进程有任务时派发给子进程工作。这样就可以节省开辟进程的花销当没有任务时即管道为空。那么子进程就是阻塞状态不会影响其他进程工作效率。但是注意我们要将任务均衡地派发给子进程即实现负载均衡Channel首先我们要设计一个方案让父进程能统一管理与子进程之间的管道最好的方法就是封装一个类。那么类的成员变量必然要有管道的写端fd、子进程的pid还可以有给子进程的编号。classChannel{public:Channel(intwfd,pid_t id,conststd::stringname):_wfd(wfd),_subprocessid(id),_name(name){}intGetWfd(){return_wfd;}pid_tGetPidProcessId(){return_subprocessid;}std::stringGetName(){return_name;}//关闭写端voidColseChannel(){close(_wfd);}//等待子进程voidWait(){pid_t ridwaitpid(_subprocessid,nullptr,0);if(rid0){std::coutwaitridsuccess!std::endl;}}~Channel(){}private:int_wfd;pid_t _subprocessid;std::string _name;};初始化接下来我们要初始化Channel数组。根据要创建的worker个数num我们可以写一个简单的for循环创建管道和子进程。由子进程关闭写端父进程关闭读端即可。但是我们要注意一个细节这里以创建两个子进程举例这里先创建第一个worker然后分别关闭读写端此时我们创建第二个worker然后分别关闭读写端这时我们发现第二个子进程对第一个管道的写端并没有关闭此时有可能造成父进程最后无法结束进程。因此我们在创建新的worker时要将前面的worker的写端关闭voidCreatChannelAndSub(intnum,std::vectorChannel*channels,task_t task){for(inti0;inum;i){intpipefd[2]{0};intnpipe(pipefd);//创建管道失败if(n0)exit(1);//创建子进程pid_t idfork();if(id0){//非空就要关闭前面的写端if(!channels-empty()){for(autochannel:*channels)channel.ColseChannel();}close(pipefd[1]);//重定向到标准输入dup2(pipefd[0],0);//回调函数task();close(pipefd[0]);exit(0);}//父进程std::string channel_nameChannel-std::to_string(i);close(pipefd[0]);channels-emplace_back(pipefd[1],id,channel_name);}}创建任务我们来实现不同的任务以分配给子进程首先重命名下函数指针用以实现回调函数随意实现三个简单的任务voidPrint(){std::coutI am print taskstd::endl;}voidDownLoad(){std::coutI am download taskstd::endl;}voidFlush(){std::coutI am flush taskstd::endl;}创建回调表分配任务intSelectTask(){returnrand()%TaskNum;}执行任务voidExcuteTask(intnumber){if(number0||number2)return;tasks[number];}子进程工作以及有了上面的一系列任务我们是时候给子进程工作了voidwork(){while(true){intcommand0;intnread(0,command,sizeof(command));if(nsizeof(int)){std::coutpid is:getpid()handler taskstd::endl;ExcuteTask(command);}//写端关闭if(n0){std::coutsub process:getpid() quitstd::endl;break;}}}轮询方案前面提到我们要实现负载均衡这里可以简单实现为轮询。即轮流给子进程派送任务intNextChannel(intchannelnum){staticintnext0;intchannelnext;next;next%channelnum;returnnext;}分配工作子进程的工作也有了轮询方案也有了就可以给子进程正是分配工作了voidSendTaskCommand(Channelchannel,inttaskcommand){write(channel.GetWfd(),taskcommand,sizeof(int));}voidctrlProcessOnce(std::vectorChannelchannels){sleep(1);//挑选任务inttaskcommandSelectTask();//挑选信道和进程intchannel_indexNextChannel(channels.size());//发送任务SendTaskCommand(channels[channel_index],taskcommand);std::coutstd::endl;std::couttaskcommand:taskcommandchannel:channels[channel_index].GetName()\sub process:channels[channel_index].GetPidProcessId()std::endl;}voidctrlProcess(std::vectorChannelchannels,inttimes-1){if(times0){while(times--)ctrlProcessOnce(channels);}else{while(true)ctrlProcessOnce(channels);}}关闭子进程和管道有了前面关闭子进程所有写端的处理我们能直接关闭子进程的读端进而使子进程退出对子进程等待即可voidCleanUpChannel(std::vectorChannelchannels){for(autochannel:channels){channel.ColseChannel();channel.Wait();}}Main接下来就是在main函数里安排代码执行的顺序,我们还可以通过选项的形式控制生成的子进程数量intmain(intargc,char*argv[]){if(argc!2){std::cerrUsage:argv[0] processnumstd::endl;}intnumstd::stoi(argv[1]);std::vectorChannelchannels;//1.创建子进程和信道CreatChannelAndSub(num,channels,work);//2.控制子进程ctrlProcess(channels,5);//3.回收资源CleanUpChannel(channels);return0;}来尝试运行代码完整代码