• 简易版的进程池


    1.使用匿名管道实现 进程池

    1. #pragma once
    2. typedef void(*task_t)();
    3. void task1()
    4. {
    5. cout << "游戏 刷新日志" << endl;
    6. }
    7. void task2()
    8. {
    9. cout << "游戏 刷新野区" << endl;
    10. }
    11. void task3()
    12. {
    13. cout << "游戏 检测软件是否更新,如果需要,就提示用户" << endl;
    14. }
    15. void task4()
    16. {
    17. cout << "游戏 用户释放技能,更新用户的HP和MP"<
    18. }
    19. void Loadtask(vector<task_t> *tasks)
    20. {
    21. tasks->push_back(task1);
    22. tasks->push_back(task2);
    23. tasks->push_back(task3);
    24. tasks->push_back(task4);
    25. }
    26. //以上是头文件
    27. //以下是程序;
    28. //类似于内存池,每次使用都不再向系统申请进程,而是提前储备进程;
    29. #include
    30. #include
    31. #include
    32. #include
    33. #include
    34. #include
    35. #include
    36. #include
    37. #include
    38. using namespace std;
    39. #include"main.h"
    40. const int processnum = 5;//子进程数量=5
    41. vector<task_t> tasks; //任务列表,全局变量
    42. //先描述
    43. class channel
    44. {
    45. public:
    46. channel(int cmdfd ,pid_t slaverid,const string &processname)
    47. :_cmdfd(cmdfd),
    48. _slaverid(slaverid),
    49. _processname(processname)
    50. {}
    51. public:
    52. int _cmdfd; //发送任务的文件描述符
    53. pid_t _slaverid; //子进程的pid
    54. string _processname;//子进程的名字——方便我们打印日志;
    55. };
    56. void slaver()
    57. {
    58. //read(0);//直接从标准输入读
    59. while (true)
    60. {
    61. int cmdcode = 0;
    62. int n = read(0,&cmdcode,sizeof(int));//如果父进程不给子进程发任务?就会阻塞等待;
    63. if (n == sizeof(int))
    64. {
    65. //执行cmdcode 对应的任务列表;
    66. cout << getpid() << ":cmdcode:" << cmdcode << endl;//查看父进程给子进程派发的任务码;
    67. if (cmdcode > 0 && cmdcode < tasks.size()) //满足条件运行函数;
    68. tasks[cmdcode]();
    69. }
    70. if (n == 0)
    71. {
    72. break;
    73. }
    74. }
    75. }
    76. //函数传参,需要输入型,输出型,输入输出型参数;
    77. //输入:const &: const引用
    78. //输出:用指针
    79. //输入输出:&引用
    80. void InitProcessPool(vector* channels)
    81. {
    82. //方法二:确保,每个子进程都只有一个写端
    83. vector<int> oldfds;
    84. //1.初始化
    85. for (int i = 0; i < processnum; i++)
    86. {
    87. int pipefd[2];//临时空间;
    88. int n = pipe(pipefd);
    89. assert(!n);//判断是否成功;
    90. (void)n;
    91. pid_t id = fork();
    92. if (id == 0)//子进程读
    93. {
    94. for (auto fd : oldfds) close(fd); //关掉写端管道;
    95. close(pipefd[1]);
    96. dup2(pipefd[0], 0); //重定向,从标准输入中读
    97. close(pipefd[0]);
    98. slaver(); //执行相对应的任务;
    99. cout << "process: " << getpid() << "quit" << endl;//打印子进程pid;退出进程;
    100. exit(0);
    101. }
    102. //父进程写入
    103. close(pipefd[0]);
    104. //添加channel字段;
    105. string name = "process-" + to_string(i);
    106. channels->push_back(channel(pipefd[1], id, name));
    107. oldfds.push_back((pipefd[1]));
    108. }
    109. }
    110. void Debug(const vector &channels)
    111. {
    112. //test
    113. for (const auto& c : channels)
    114. {
    115. cout << c._cmdfd << " " << c._slaverid << " " << c._processname << endl;
    116. }
    117. }
    118. void Menu() //菜单
    119. {
    120. cout << "1.刷新日志" << endl;
    121. cout << "2.刷新野怪" << endl;
    122. cout << "3.检测更新" << endl;
    123. cout << "4.更新状态" << endl;
    124. cout << "0.退出游戏" << endl;
    125. }
    126. //控制子进程
    127. void ctrlSlaver(const vector& channels)
    128. {
    129. int which = 0;
    130. //int cnt = 5;
    131. while(true)
    132. {
    133. int select = 0;
    134. Menu(); //手动控制
    135. cout << "please Enter@" << endl;
    136. cin >> select;
    137. if (select <= 0 || select >= 5) break;
    138. //select >0 &&select<5
    139. //1.选择任务
    140. //int cmdcode = rand() % tasks.size();//创造一个随机数,当作任务;
    141. int cmdcode = select-1;
    142. //2.选择进程(负载均衡:不可以一直给某个进程派发任务,其他进程都闲着,要均衡发展这个叫做负载均衡)1.使用随机数 2.轮转l来实现负载均衡
    143. //int processpos = rand() % channels.size(); //随机数
    144. //cout << "father say:" << "cmdcode:" << cmdcode << "already send to" << channels[processpos]._slaverid << endl;
    145. cout << "father say:" << "cmdcode:" << cmdcode << "already send to" << channels[which]._slaverid << endl;//轮转
    146. //3.发送任务
    147. //write(channels[processpos]._cmdfd, &cmdcode, sizeof(cmdcode)); //随机数版本
    148. write(channels[which]._cmdfd, &cmdcode, sizeof(cmdcode)); //轮转
    149. which++;
    150. which %= channels.size();
    151. //cnt--;
    152. //sleep(1);
    153. }
    154. }
    155. void QuitProcess(const vector &channels) //退出进程
    156. {
    157. //方法1:倒着回收
    158. int last = channels.size() - 1;
    159. for (int i = last; i >= 0; i--)
    160. {
    161. close(channels[i]._cmdfd);
    162. waitpid(channels[i]._slaverid, nullptr, 0);
    163. }
    164. //方法二:在初始化时关闭子进程多余的管道;
    165. //for (const auto& c : channels)
    166. //{
    167. // close(c._cmdfd);
    168. //}
    169. //for (const auto& c : channels) waitpid(c._slaverid, nullptr, 0); //等待退出
    170. }
    171. int main()
    172. {
    173. Loadtask(&tasks); //加载任务参数;
    174. srand(time(nullptr) ^ getpid() ^ 1023); //种一个随机数种子
    175. //再组织
    176. vector channels;
    177. //初始化-------bug?————画图就可以看出来,推荐画一下图!!!答:文件描述符随着创建子进程递增;
    178. InitProcessPool(&channels); //初始化
    179. Debug(channels); //测试
    180. //2.开始控制子进程
    181. ctrlSlaver(channels); //控制子进程
    182. //3.清理收尾
    183. QuitProcess(channels);
    184. return 0;
    185. }

  • 相关阅读:
    C语言中的文件操作
    Yield Guild Games:社区更新——2022 年第 3 季度
    十四、城市建成区时空扩张分析——景观格局指数
    Flink UDF函数
    C语言只推荐这1本宝藏书,你读过吗?
    第五章 树 1 AcWing 1476. 数叶子结点
    【学习笔记】深度学习入门:基于Python的理论与实现-与学习相关的技巧
    第11章 调试
    (c++)类和对象中篇
    江西农业大学择校分析(附23招生简章)
  • 原文地址:https://blog.csdn.net/qincjun/article/details/139373226