1.使用匿名管道实现 进程池
- #pragma once
-
- typedef void(*task_t)();
-
- void task1()
- {
- cout << "游戏 刷新日志" << endl;
- }
-
- void task2()
- {
- cout << "游戏 刷新野区" << endl;
- }
- void task3()
- {
- cout << "游戏 检测软件是否更新,如果需要,就提示用户" << endl;
- }
- void task4()
- {
- cout << "游戏 用户释放技能,更新用户的HP和MP"<
- }
- void Loadtask(vector<task_t> *tasks)
- {
- tasks->push_back(task1);
- tasks->push_back(task2);
- tasks->push_back(task3);
- tasks->push_back(task4);
- }
-
- //以上是头文件
-
- //以下是程序;
- //类似于内存池,每次使用都不再向系统申请进程,而是提前储备进程;
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
-
- using namespace std;
- #include"main.h"
- const int processnum = 5;//子进程数量=5
- vector<task_t> tasks; //任务列表,全局变量
-
- //先描述
- class channel
- {
- public:
- channel(int cmdfd ,pid_t slaverid,const string &processname)
- :_cmdfd(cmdfd),
- _slaverid(slaverid),
- _processname(processname)
- {}
- public:
- int _cmdfd; //发送任务的文件描述符
- pid_t _slaverid; //子进程的pid
- string _processname;//子进程的名字——方便我们打印日志;
- };
-
- void slaver()
- {
- //read(0);//直接从标准输入读
- while (true)
- {
- int cmdcode = 0;
- int n = read(0,&cmdcode,sizeof(int));//如果父进程不给子进程发任务?就会阻塞等待;
- if (n == sizeof(int))
- {
- //执行cmdcode 对应的任务列表;
- cout << getpid() << ":cmdcode:" << cmdcode << endl;//查看父进程给子进程派发的任务码;
- if (cmdcode > 0 && cmdcode < tasks.size()) //满足条件运行函数;
- tasks[cmdcode]();
- }
- if (n == 0)
- {
- break;
- }
- }
- }
- //函数传参,需要输入型,输出型,输入输出型参数;
- //输入:const &: const引用
- //输出:用指针
- //输入输出:&引用
- void InitProcessPool(vector
* channels) - {
- //方法二:确保,每个子进程都只有一个写端
- vector<int> oldfds;
- //1.初始化
- for (int i = 0; i < processnum; i++)
- {
- int pipefd[2];//临时空间;
- int n = pipe(pipefd);
- assert(!n);//判断是否成功;
- (void)n;
-
- pid_t id = fork();
- if (id == 0)//子进程读
- {
- for (auto fd : oldfds) close(fd); //关掉写端管道;
- close(pipefd[1]);
- dup2(pipefd[0], 0); //重定向,从标准输入中读
- close(pipefd[0]);
- slaver(); //执行相对应的任务;
- cout << "process: " << getpid() << "quit" << endl;//打印子进程pid;退出进程;
- exit(0);
- }
- //父进程写入
- close(pipefd[0]);
-
- //添加channel字段;
- string name = "process-" + to_string(i);
- channels->push_back(channel(pipefd[1], id, name));
- oldfds.push_back((pipefd[1]));
- }
- }
- void Debug(const vector
&channels) - {
- //test
- for (const auto& c : channels)
- {
- cout << c._cmdfd << " " << c._slaverid << " " << c._processname << endl;
- }
- }
- void Menu() //菜单
- {
- cout << "1.刷新日志" << endl;
- cout << "2.刷新野怪" << endl;
- cout << "3.检测更新" << endl;
- cout << "4.更新状态" << endl;
- cout << "0.退出游戏" << endl;
- }
- //控制子进程
- void ctrlSlaver(const vector
& channels) - {
- int which = 0;
- //int cnt = 5;
- while(true)
- {
- int select = 0;
- Menu(); //手动控制
- cout << "please Enter@" << endl;
- cin >> select;
-
- if (select <= 0 || select >= 5) break;
- //select >0 &&select<5
-
- //1.选择任务
- //int cmdcode = rand() % tasks.size();//创造一个随机数,当作任务;
- int cmdcode = select-1;
-
- //2.选择进程(负载均衡:不可以一直给某个进程派发任务,其他进程都闲着,要均衡发展这个叫做负载均衡)1.使用随机数 2.轮转l来实现负载均衡
-
- //int processpos = rand() % channels.size(); //随机数
- //cout << "father say:" << "cmdcode:" << cmdcode << "already send to" << channels[processpos]._slaverid << endl;
-
- cout << "father say:" << "cmdcode:" << cmdcode << "already send to" << channels[which]._slaverid << endl;//轮转
-
- //3.发送任务
- //write(channels[processpos]._cmdfd, &cmdcode, sizeof(cmdcode)); //随机数版本
- write(channels[which]._cmdfd, &cmdcode, sizeof(cmdcode)); //轮转
- which++;
- which %= channels.size();
- //cnt--;
- //sleep(1);
- }
- }
- void QuitProcess(const vector
&channels) //退出进程 - {
- //方法1:倒着回收
- int last = channels.size() - 1;
- for (int i = last; i >= 0; i--)
- {
- close(channels[i]._cmdfd);
- waitpid(channels[i]._slaverid, nullptr, 0);
- }
- //方法二:在初始化时关闭子进程多余的管道;
-
- //for (const auto& c : channels)
- //{
- // close(c._cmdfd);
- //}
- //for (const auto& c : channels) waitpid(c._slaverid, nullptr, 0); //等待退出
- }
-
- int main()
- {
- Loadtask(&tasks); //加载任务参数;
- srand(time(nullptr) ^ getpid() ^ 1023); //种一个随机数种子
- //再组织
- vector
channels; -
- //初始化-------bug?————画图就可以看出来,推荐画一下图!!!答:文件描述符随着创建子进程递增;
- InitProcessPool(&channels); //初始化
- Debug(channels); //测试
-
- //2.开始控制子进程
- ctrlSlaver(channels); //控制子进程
-
- //3.清理收尾
- QuitProcess(channels);
- return 0;
- }