网站怎么设置手机模板管理江干区住房和城乡建设局网站

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

网站怎么设置手机模板管理,江干区住房和城乡建设局网站,做网站需要写代码,跨国浏览器目录 一、池化技术 二、简易进程池的实现#xff1a; Makefile task.h task.cpp Initchannel函数#xff1a; 创建任务#xff1a; 控制子进程#xff1a; 子进程执行任务#xff1a; 清理收尾#xff1a; 三、全部代码#xff1a; 前言#xff1a; 对于管…目录 一、池化技术 二、简易进程池的实现 Makefile task.h task.cpp Initchannel函数 创建任务 控制子进程 子进程执行任务 清理收尾 三、全部代码 前言 对于管道我们已经学习了匿名管道那么这个匿名管道有什么用呢接下来我们以池化技术来实现一个简易的管道进程池 一、池化技术 1、内存池减少内存分配的系统调用开销 问题 当使用new或  malloc 动态分配内存时每次都会触发系统调用 例如每次申请5字节或者申请10字节再次申请20字节会触发三次系统调用 系统调用成本高因为操作系统可能正在处理其他任务导致等待降低效率 解决方案 一次性向操作系统申请更大的内存空间如100字节或200字节 后续需要内存时直接从这块预先申请好的空间中分配避免频繁触发系统调用 优点 减少系统调用次数分摊开销提高内存分配效率 2、进程池减少进程创建的开销 问题 传统方式是父进程创建子进程子进程完成任务后退出父进程等待 每次创建子进程时操作系统需要复制task_struct页表等数据结构开销较大 频繁创建和销毁进程效率低下 解决方案 预先创建一批子进程作为资源储备进程池 当有任务到来时父进程直接将任务分配给池中已有的子进程而不是每次都创建新进程 优点 减少进程创建的开销提高任务分配和执行的效率

  1. 核心思想 资源预分配 无论是内存池还是进程池核心思想都是预先分配资源避免重复的系统调用或资源创建 提高效率 通过减少高频操作的开销显著提升程序性能尤其适用于高并发或高性能场景 总结 内存池一次性申请大块内存后续直接从池中分配减少系统调用 进程池预先创建一批进程任务到来时直接分配减少进程创建开销 共同目标通过资源预分配优化性能降低系统开销 二、简易进程池的实现 在了解上述的池化技术后我们以这种思想来设计一个简易的进程池 如上这是一个简易的进程池我们让父进程向子进程发送数据也就是父进程向管道中写入数据然后子进程从管道中读数据这样父进程创建多个子进程每次选择某个子进程和管道进行数据的传输这样就是一个简易的进程池了 Makefile task:tesk.cppg -o \( \)^ -g -stdc11 .PHONY:clean clean:rm -f tasktask.h #pragma once #includeiostream #includevector #includestring task.cpp 先描述 首先通过class类来描述一个管道 #includetask.h//先描述描述管道 class channel { public://构造函数通过列表进行初始化channel(int fd, int childpid, const std::string processname):_fd(fd),_childpid(childpid),_processname(processname){} public:int _fd; //管道写端的文件描述符pid_t _childpid; //管道所连接表示子进程的pidstd::string _processname; //管道所连接的子进程的名字 };int main() {//加载好任务//通过vector将一个个管道组织起来std::vectorchannel channels;//初始化创建管道Initchannel(channels);//控制子进程ctrlchild(channels);//清理收尾quitprocess(channels);return 0; } 在组织 在通过vector这个容器来将一个个管道组织起来然后进行初始化控制子进程清理等操作 Initchannel函数 创建管道这个管道是连接父进程和子进程的所以我们要创建几个管道就需要创建几个子进程 通过pipe创建管道文件 初始化 void Initchannel(std::vectorchannel* channels) {for(int i 0;iprocessnum;i){//创建管道int pipefd[2];int n pipe(pipefd);//创建管道文件if(n ! 0) exit(0);//创建失败就退出程序//创建完管道文件然后创建管道文件对应的子进程pid_t id fork();if(id 0){//子进程模块这里子进程去读所以关闭写通道close(pipefd[1]);//重定向dup2(pipefd[0],0);work();//子进程进行工作的函数模块exit(0);//工作完就结束子进程}//父进程去写所以这里关闭读端close(pipefd[0]);std::string name processstd::to_string(i);channels-push_back(channel(pipefd[1],id,name));} } 创建任务 //重定义函数指针 typedef void(* task)();void task1() {std::cout刷新野区std::endl; }void task2() {std::cout刷新技能std::endl; }void task3() {std::cout泉水回血std::endl; }void task4() {std::cout技能耗蓝std::endl; }void Loadtask(std::vectortask* tasks) {tasks-push_back(task1);tasks-push_back(task2);tasks-push_back(task3);tasks-push_back(task4); } 其中Loadtask函数的作用就是保存所执行的任务 接着在程序最开始也就是在main函数的最开始将我们的任务都进行加载好 还需要全局变量 processnum 控制进程池的大小决定创建多少个子进程。 方便扩展例如通过配置文件动态设置子进程数量。 tasks 集中管理所有任务便于父进程和子进程共享任务列表。 通过任务码索引快速定位和执行任务。 const int processnum 5;//进程中子进程的数量 std::vectortask tasks;//存储任务的容器int main() {//加载好任务Loadtask(tasks);//通过vector将一个个管道组织起来std::vectorchannel channels;//初始化创建管道Initchannel(channels);//控制子进程ctrlchild();//清理收尾quitprocess();return 0; } 手动控制子进程 这里首先搞一个菜单出来 void menu() {std::cout ######################################### std::endl;std::cout # 1、刷新野区 2、刷新技能 # std::endl;std::cout # 3、泉水回血 4、技能耗蓝 # std::endl;std::cout # 0、退出 # std::endl;std::cout ######################################### std::endl; } 在控制子进程的过程中我们首先选好我们要完成的任务然后向管道里写一个任务码然后被选中的子进程就会从管道中找到任务码就可以根据vectortask里面的任务知道需要执行哪一个任务了 控制子进程 根据菜单每次输入任务码的时候就通过write系统调用来确定子进程发送任务 void ctrlchild(std::vectorchannel channels) {int which 0;while(1){menu();int selet 0;std::cout请输入所选择的任务;std::cinselet;//判断所选的任务码是否合法if(selet0 || selet5) break;//任务选择int taskcode selet - 1;//子进程选择,轮询法std::coutfather say taskcode : taskcode already send to channels[which]._childpid process name channels[which]._processname std::endl;//发送任务write(channels[which]._fd,taskcode,sizeof(taskcode));//确定子进程子进程所接收的任务码和所接受的大小//保证所选的进程合法which;which % channels.size();} } 子进程执行任务 这是子进程的核心代码通过read系统调用接口从管道中读到任务码在通过这个任务码和函数指针来调用任务 //子进程工作代码通过父进程向管道发送的任务码找到对应的任务然后执行 void work() {while(1){int teskcode 0;int n read(0, teskcode, sizeof(teskcode)); //read返回的是读取到的字节的个数。 //然后第二个参数是要读到哪里去第三个参数是读取的大小,这一行代码执行完后teskcode里面保存的就是要执行的任务码if (n sizeof(teskcode)){std::cout work get a command : getpid() : teskcode teskcode std::endl;if (teskcode 0 teskcode tasks.size()) tasksteskcode;}if (n 0) break; //如果读到0 说明写端关闭 读端读到文件末尾 就需要停止读取了} }清理收尾 在清理收尾的时候不能够直接关闭然后父进程等待子进程这样是有问题的因为当父进程创建子进程的时候子进程的读端也会指向对应的管道这样的话一个管道就会有很多个读端了如下 每一个子进程的写端都会指向之前的所有管道比如如果上述有3个进程的话那么第一个管道就有3个写端父进程一个父进程创建的两个子进程的写端都会指向第一个管道那么如果直接close(c._fd)关闭管道的写端的话那么是不能够关闭完全的需要全部关闭这里有两种解决方式 第一种方式 从后往前进行关闭下面代码已给出我们知道最后一个管道依然是只有一个写端的那么当最后一个管道关闭后前面的管道的写端就都会少一个这样的话从后往前关闭就不会出现这样的问题了 void quitprocess(const std::vectorchannel channels) {//出现问题for(const auto c : channels){close(c._fd); waitpid(c._childpid,nullptr,0);}// //解决方案1// int last channels.size()-1;// for(int i last;i0;i–)// {// close(channels[i]._fd);// waitpid(channels[i]._childpid,nullptr,0);// }// for(const auto c : channels)// {// close(c._fd);// }// for(const auto c : channels)// {// waitpid(c._childpid,nullptr,0);// } }第二种方式 在创建管道的时候进行记录父进程所占用的文件描述符 三、全部代码 makefile task:task.cppg -o \( \)^ -g -stdc11 .PHONY:clean clean:rm -f tasktask.h #pragma once #includeiostream #includevector #includestring#includeunistd.h #includesys/types.h #includesys/wait.h//重定义函数指针 typedef void(* task)();void task1() {std::cout刷新野区std::endl; }void task2() {std::cout刷新技能std::endl; }void task3() {std::cout泉水回血std::endl; }void task4() {std::cout技能耗蓝std::endl; }//保存所执行的任务 void Loadtask(std::vectortask* tasks) {tasks-push_back(task1);tasks-push_back(task2);tasks-push_back(task3);tasks-push_back(task4); } task.cpp #includetask.hconst int processnum 5; std::vectortask tasks; //先描述描述管道 class channel { public://构造函数通过列表进行初始化channel(int fd, int childpid, const std::string processname):_fd(fd),_childpid(childpid),_processname(processname){} public:int _fd; //表示父进程链接某个管道的fdpid_t _childpid; //管道所连接表示子进程的pidstd::string _processname; //管道所连接的子进程的名字 };//子进程工作代码通过父进程向管道发送的任务码找到对应的任务然后执行 void work() {while(1){int teskcode 0;int n read(0, teskcode, sizeof(teskcode)); //read返回的是读取到的字节的个数。 //然后第二个参数是要读到哪里去第三个参数是读取的大小,这一行代码执行完后teskcode里面保存的就是要执行的任务码if (n sizeof(teskcode)){std::cout work get a command : getpid() : teskcode teskcode std::endl;if (teskcode 0 teskcode tasks.size()) tasksteskcode;}if (n 0) break; //如果读到0 说明写端关闭 读端读到文件末尾 就需要停止读取了} }void Initchannel(std::vectorchannel* channels) {//解决方案2std::vectorint oldfd;//创建一个数组记录父进程所在的文件描述符的写端for(int i 0;iprocessnum;i){//创建管道int pipefd[2];int n pipe(pipefd);//创建管道文件if(n ! 0) exit(0);//创建失败就退出程序//创建完管道文件然后创建管道文件对应的子进程pid_t id fork();if(id 0){//将父进程所在的文件描述符写端子进程将其关闭for(auto fd : oldfd) close(fd);//子进程模块这里子进程去读所以关闭写通道close(pipefd[1]);//重定向dup2(pipefd[0],0);work();//子进程进行工作的函数模块std::cout Process PID: getpid() quit std::endl;exit(0);//工作完就结束子进程}//父进程去写所以这里关闭读端close(pipefd[0]);std::string name processstd::to_string(i);channels-push_back(channel(pipefd[1],id,name));//每次记录父进程写端所在的文件描述符oldfd.push_back(pipefd[1]); } }void menu() {std::cout ######################################### std::endl;std::cout # 1、刷新野区 2、刷新技能 # std::endl;std::cout # 3、泉水回血 4、技能耗蓝 # std::endl;std::cout # 0、退出 # std::endl;std::cout ######################################### std::endl; }void ctrlchild(std::vectorchannel channels) {int which 0;while(1){menu();int selet 0;std::cout请输入所选择的任务;std::cinselet;//判断所选的任务码是否合法if(selet0 || selet5) break;//任务选择int taskcode selet - 1;//子进程选择,轮询法std::coutfather say taskcode : taskcode already send to channels[which]._childpid process name channels[which]._processname std::endl;//发送任务write(channels[which]._fd,taskcode,sizeof(taskcode));//确定子进程子进程所接收的任务码和所接受的大小//保证所选的进程合法which;which % channels.size();} }void quitprocess(const std::vectorchannel channels) {//出现问题for(const auto c : channels){close(c._fd); waitpid(c._childpid,nullptr,0);}// //解决方案1// int last channels.size()-1;// for(int i last;i0;i–)// {// close(channels[i]._fd);// waitpid(channels[i]._childpid,nullptr,0);// }// for(const auto c : channels)// {// close(c._fd);// }// for(const auto c : channels)// {// waitpid(c._childpid,nullptr,0);// } }int main() {//加载好任务Loadtask(tasks);//通过vector将一个个管道组织起来std::vectorchannel channels;//初始化创建管道Initchannel(channels);//控制子进程ctrlchild(channels);//清理收尾quitprocess(channels);return 0; }