网站基本框架,wordpress插件 产品,一个人可以建设几个网站,怎么看一个网站是不是外包做的一、进程池的设计 因为每一次我们要进行进程间通信都需要fork#xff0c;和操作系统做交互是存在很大成本的#xff0c;所以我们是不是可以提前fork出几个进程#xff0c;然后当我们想要使用的时候直接去给他们安排任务#xff0c;这样就减少了系统调用的次数从而提高了内存…
一、进程池的设计 因为每一次我们要进行进程间通信都需要fork和操作系统做交互是存在很大成本的所以我们是不是可以提前fork出几个进程然后当我们想要使用的时候直接去给他们安排任务这样就减少了系统调用的次数从而提高了内存申请速度 父进程和多个子进程建立管道之后 父进程只需要1选择任务 2选择进程
1、 先描述管道 2、加载任务 3、初始化进程池 管道继承下去打开的写端都是3号fd 为了让子进程没有管道的概念我们直接用dup来将子进程的标准输入改成管道文件这样可以让子进程没有管道的概念我们也就可以直接无脑从0号fd读取 4、子进程完成任务 5、父进程控制子进程
6、菜单 7、结束进程 为什么正着回收不行呢——因为子进程会把父进程指向前面管道的写端继承下去 所以2号继承会有指向1号进程写端的fd 3号继承会有1号和2号进程写端的fd…… 所以到10号的时候就会有9个进程写端的fd 所以第一个子进程被回收的时候会因为一些子进程的写端没有关闭而造成阻塞 ·
解决方案1倒着回收
解决方案2两个循环先把所有写端关闭了再一起回收
解决方案3确保子进程只有一个写端就是在创建的时候就把指向前面几个进程的写端全部关掉 8 、负载均衡
随机数种子轮转 或者是 让进程轮流工作 整体代码
#pragma once#include iostream
#include vectortypedef void (*task_t)();void task1()
{std::cout lol 刷新日志 std::endl;
}
void task2()
{std::cout lol 更新野区刷新出来野怪 std::endl;
}
void task3()
{std::cout lol 检测软件是否更新,如果需要就提示用户 std::endl;
}
void task4()
{std::cout lol 用户释放技能更新用的血量和蓝量 std::endl;
}void LoadTask(std::vectortask_t *tasks)
{tasks-push_back(task1);tasks-push_back(task2);tasks-push_back(task3);tasks-push_back(task4);
} #include Task.hpp
#include string
#include vector
#include cstdlib
#include ctime
#include cassert
#include unistd.h
#include sys/stat.h
#include sys/wait.hconst int processnum 10;
std::vectortask_t tasks;// 先描述
class channel
{
public:channel(int cmdfd, int slaverid, const std::string processname):_cmdfd(cmdfd), _slaverid(slaverid), _processname(processname){}
public:int _cmdfd; // 发送任务的文件描述符pid_t _slaverid; // 子进程的PIDstd::string _processname; // 子进程的名字 -- 方便我们打印日志// int _cmdcnt;
};void slaver()
{// read(0)while(true){int cmdcode 0;int n read(0, cmdcode, sizeof(int)); // 如果父进程不给子进程发送数据呢阻塞等待if(n sizeof(int)){//执行cmdcode对应的任务列表std::cout slaver say get a command: getpid() : cmdcode: cmdcode std::endl;if(cmdcode 0 cmdcode tasks.size()) tasks[cmdcode]();}if(n 0) break;}
}
// 输入const
// 输出*
// 输入输出
void InitProcessPool(std::vectorchannel *channels)
{// version 2: 确保每一个子进程都只有一个写端std::vectorint oldfds;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) // child{std::cout child: getpid() close history fd: ;for(auto fd : oldfds) {std::cout fd ;close(fd);}std::cout \n;close(pipefd[1]);dup2(pipefd[0], 0);close(pipefd[0]);slaver();std::cout process : getpid() quit std::endl;// slaver(pipefd[0]);exit(0);}// fatherclose(pipefd[0]);// 添加channel字段了std::string name process- std::to_string(i);channels-push_back(channel(pipefd[1], id, name));oldfds.push_back(pipefd[1]);sleep(1);}
}void Debug(const std::vectorchannel channels)
{// testfor(const auto c :channels){std::cout c._cmdfd c._slaverid c._processname std::endl;}
}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 ctrlSlaver(const std::vectorchannel channels)
{int which 0;// int cnt 5;while(true){int select 0;Menu();std::cout Please Enter ;std::cin select;if(select 0 || select 5) break;// select 0 select 5// 1. 选择任务// int cmdcode rand()%tasks.size();int cmdcode select - 1;// 2. 选择进程// int processpos rand()%channels.size();std::cout father say: cmdcode: cmdcode already sendto channels[which]._slaverid process name: channels[which]._processname std::endl;// 3. 发送任务write(channels[which]._cmdfd, cmdcode, sizeof(cmdcode));which;which % channels.size();// cnt--;// sleep(1);}
}void QuitProcess(const std::vectorchannel channels)
{for(const auto c : channels){close(c._cmdfd);waitpid(c._slaverid, nullptr, 0);}// version1 // 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);// // sleep(5);// for(const auto c : channels) waitpid(c._slaverid, nullptr, 0);// // sleep(5);
}
int main()
{LoadTask(tasks);srand(time(nullptr)^getpid()^1023); // 种一个随机数种子// 在组织std::vectorchannel channels;// 1. 初始化 --- bug?? -- 找一下这个问题在哪里然后提出一些解决方案InitProcessPool(channels);// Debug(channels);// 2. 开始控制子进程ctrlSlaver(channels);// 3. 清理收尾QuitProcess(channels);return 0;
}
二、日志的设计
1、什么是日志
日志的时间、日志的等级、日志的内容、文章的名称和行号 帮助我们能够看到一些代码运行过程中的重要信息。 2、设置等级和写日志的方式 因为我们的日志信息可能会需要各种类型 比如%d %s…… 所以必须用到可变参数。且格式化为字符串。 且日志一般情况下是写到文件里的 也有可能要按照等级去分文件因此 3、可变参数列表的解析举例 4、日志信息的前半部分时间
time是获取一个时间戳
gettimeofday获取当天的时间tv是输出型参数
settimeofday设置当天的时间 tv是输入型参数 localtime 把time类型的返回值传过来 转化成tm结构返回 有具体的时间信息 leftbuffer是左半部分的时间信息可以用格式化snprintf rightbuffer是右半部分的日志信息可变参数 vsnprintf。 可以用运算符重载美化一下这样调用的时候就更方便 5、想办法把文件打包 #pragma once#include iostream
#include time.h
#include stdarg.h
#include sys/types.h
#include sys/stat.h
#include fcntl.h
#include unistd.h
#include stdlib.h#define SIZE 1024#define Info 0
#define Debug 1
#define Warning 2
#define Error 3
#define Fatal 4#define Screen 1
#define Onefile 2
#define Classfile 3#define LogFile log.txtclass Log
{
public:Log(){printMethod Screen;path ./log/;}void Enable(int method){printMethod method;}std::string levelToString(int level){switch (level){case Info:return Info;case Debug:return Debug;case Warning:return Warning;case Error:return Error;case Fatal:return Fatal;default:return None;}}// void logmessage(int level, const char *format, ...)// {// time_t t time(nullptr);// struct tm *ctime localtime(t);// char leftbuffer[SIZE];// snprintf(leftbuffer, sizeof(leftbuffer), [%s][%d-%d-%d %d:%d:%d], levelToString(level).c_str(),// ctime-tm_year 1900, ctime-tm_mon 1, ctime-tm_mday,// ctime-tm_hour, ctime-tm_min, ctime-tm_sec);// // va_list s;// // va_start(s, format);// char rightbuffer[SIZE];// vsnprintf(rightbuffer, sizeof(rightbuffer), format, s);// // va_end(s);// // 格式默认部分自定义部分// char logtxt[SIZE * 2];// snprintf(logtxt, sizeof(logtxt), %s %s\n, leftbuffer, rightbuffer);// // printf(%s, logtxt); // 暂时打印// printLog(level, logtxt);// }void printLog(int level, const std::string logtxt){switch (printMethod){case Screen:std::cout logtxt std::endl;break;case Onefile:printOneFile(LogFile, logtxt);break;case Classfile:printClassFile(level, logtxt);break;default:break;}}void printOneFile(const std::string logname, const std::string logtxt){std::string _logname path logname;int fd open(_logname.c_str(), O_WRONLY | O_CREAT | O_APPEND, 0666); // log.txtif (fd 0)return;write(fd, logtxt.c_str(), logtxt.size());close(fd);}void printClassFile(int level, const std::string logtxt){std::string filename LogFile;filename .;filename levelToString(level); // log.txt.Debug/Warning/FatalprintOneFile(filename, logtxt);}~Log(){}void operator()(int level, const char *format, ...){time_t t time(nullptr);struct tm *ctime localtime(t);char leftbuffer[SIZE];snprintf(leftbuffer, sizeof(leftbuffer), [%s][%d-%d-%d %d:%d:%d], levelToString(level).c_str(),ctime-tm_year 1900, ctime-tm_mon 1, ctime-tm_mday,ctime-tm_hour, ctime-tm_min, ctime-tm_sec);va_list s;va_start(s, format);char rightbuffer[SIZE];vsnprintf(rightbuffer, sizeof(rightbuffer), format, s);va_end(s);// 格式默认部分自定义部分char logtxt[SIZE * 2];snprintf(logtxt, sizeof(logtxt), %s %s\n, leftbuffer, rightbuffer);// printf(%s, logtxt); // 暂时打印printLog(level, logtxt);}private:int printMethod;std::string path;
};// int sum(int n, ...)
// {
// va_list s; // char*
// va_start(s, n);// int sum 0;
// while(n)
// {
// sum va_arg(s, int); // printf(hello %d, hello %s, hello %c, hello %d,, 1, hello, c, 123);
// n--;
// }// va_end(s); //s NULL
// return sum;
// }