thread_pool.h
#pragma once
#include <iostream>
#include <queue>
#include <thread>
#include <functional>
#include <mutex>
#include <vector>
#include <unistd.h>
#include <condition_variable>
#include "task.h"
using namespace std;
using namespace placeholders;
#define numdefault 5
template <class T>
class thread_pool
{
public:
thread_pool(int num = numdefault)
: _num(num), _vt(num)
{
for (int i = 0; i < _num; i++)
{
string name = "thread_";
name += to_string(i + 1);
// 移动赋值,线程不支持左值拷贝
_vt[i] = thread(&thread_pool<T>::task_execution, this, name); // 成员函数默认第一个参数是this指针,所以要显式传参
// _vt[i] = thread(bind(&thread_pool<T>::task_execution, this,_1), name);//bind可以与function功能一样,不过可以提前确定参数
}
}
void task_execution(const string &args) // 多个线程开始任务执行
{
while (1)
{
T t;//调用默认构造
{
//共享代码段
unique_lock<mutex> ul(_mtx);
while (_qt.empty()) // 无任务就等待
{
cond.wait(ul); // 等待期间会解锁,多线程会再等待队列中阻塞,等待成功会上锁
}
t = _qt.front();
_qt.pop();
}
// 处理任务
t();
cout<<args<<": ";
t.print_task_finish();
sleep(1);
}
}
void push(const T &t)//传任务
{
unique_lock<mutex> ul(_mtx);
_qt.push(t);
cond.notify_one();//有任务则条件满足
}
~thread_pool()//
{
for (int i = 0; i < _num; i++) // C++11 使用thread不join的话程序会崩溃
{
_vt[i].join();
}
}
private:
int _num; // 线程数目
queue<T> _qt; // 任务管理
vector<thread> _vt; // 管理线程
mutex _mtx; // 锁
condition_variable cond; // 条件变量,任务为空等待
};
task.h
#pragma once
#include <iostream>
#include"Log.h"
using namespace std;
char operates[] = {'+', '-', '*', '/', '%', '&', '~', '|', '!', '^'};
class task
{
public:
task() {} // 需要一个默认的构造函数
task(int x, int y, char operat)
: _x(x), _y(y), _operat(operat)
{
l.enable(0);//日志在显示器打印
}
void operator()()
{
switch (_operat)
{
case '+':
_result = _x + _y;
break;
case '-':
_result = _x - _y;
break;
case '*':
_result = _x * _y;
break;
case '/':
{
if (_y == 0)
{
_s = "除数为0";
}
else
_result = _x / _y;
}
break;
case '&':
_result = _x & _y;
break;
case '|':
_result = _x | _y;
break;
case '^':
_result = _x ^ _y;
break;
default:
_s = "目前未录入该操作";
break;
}
}
void print_task_finish()
{
if (_s.empty())
cout << _x << _operat << _y << " = " << _result ;
else
cout << _s ;
l.Log_infom(Info," ");
}
void print_task_start()
{
cout << _x << _operat << _y << " = ???";
l.Log_infom(Info," ");
}
~task()
{
}
private:
int _x;
int _y;
int _result;
string _s; // 存放错误信息
char _operat;
};
Log.h
#pragma once
#include <iostream>
#include <time.h>
#include <map>
#include <stdarg.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
using namespace std;
enum // 可以设置日志等级
{
Debug,
Info,
Warning,
Error,
Fatal
};
enum//打印方式
{
Screen,
onlyfile,
classifyfile
};
const string logdir="log";//目录文件
class Log
{
public:
Log()
{
levermap[Debug] = "Debug";
levermap[Info] = "Info";
levermap[Warning] = "Warning";
levermap[Error] = "Error";
levermap[Fatal] = "Fatal";
mkdir(logdir.c_str(),0777);//创建目录,并在指定目录下打印
}
void exchange(string &s, tm *&cur_time)//时间戳转换成标准时间
{
s = to_string(cur_time->tm_year + 1900) + '/' + to_string(cur_time->tm_mon) + '/' + to_string(cur_time->tm_mday) + '-' + to_string(cur_time->tm_hour) + ':' + to_string(cur_time->tm_min) + ':' + to_string(cur_time->tm_sec);
}
void write_way(const string &filename, const string &loginfo)//文件打印
{
int fd = open(filename.c_str(), O_WRONLY | O_APPEND | O_CREAT, 0666);
if (fd == -1)
cout << "文件打开失败" << endl;
write(fd, loginfo.c_str(), loginfo.size());
close(fd);
}
void write_log(int lever, const string &loginfo)//日志写入位置
{
string tmp = logdir+'/'+"log.";
switch (style)
{
case 0://显示器打印
cout << loginfo;
break;
case 1://log.txt里打印
write_way(tmp + "txt", loginfo);
break;
case 2://分类到各自对应的文件里打印
write_way(tmp + levermap[lever], loginfo);
break;
default:
break;
}
}
void enable(int sty)
{
style = sty;
}
void Log_infom(int lever, const char *format, ...) // 格式formats
{
char tmp[1024];
va_list args; // 可变参数部分的起始地址
va_start(args, format); // 初始化,通过format确定可变参数个数
vsnprintf(tmp, sizeof(tmp), format, args); // 将数据写到tmp中
va_end(args); //
time_t t = time(nullptr); // 得到当前的时间戳
tm *cur_time = localtime(&t); // 传入时间戳
string s;
exchange(s, cur_time); // 转换成具体的时间
string loginfo;
loginfo = loginfo + tmp + ' ' + '[' + levermap[lever] + ']' + '[' + s + ']' + '\n';
write_log(lever, loginfo);
}
~Log()
{
}
private:
map<int, string> levermap;
int style = 0;//默认往显示器中打印
int lever=Debug;
};
Log l;
test.cpp
#include"thread_pool.h"
#include<time.h>
#include<cstdlib>
void test_log()
{
l.enable(0);
l.Log_infom(Debug,"haha %d,i am %s,what is %f",37,"cr",3.7);
l.Log_infom(Debug,"haha %d,i am %s,what is %f",37,"cr",3.7);
l.Log_infom(Debug,"haha %d,i am %s,what is %f",37,"cr",3.7);
l.Log_infom(Info,"haha %d,i am %s,what is %f",37,"cr",3.7);
l.Log_infom(Warning,"haha %d,i am %s,what is %f",37,"cr",3.7);
l.Log_infom(Error,"haha %d,i am %s,what is %f",37,"cr",3.7);
l.Log_infom(Fatal,"haha %d,i am %s,what is %f",37,"cr",3.7);
}
void publish(const string& name)
{
thread_pool<task> tp;
srand(time(nullptr));
while(1)
{
int x=rand()%101;
int y=rand()%101;
char operat=operates[rand()%sizeof(operates)];
task t(x,y,operat);
cout<<name<<": ";
t.print_task_start();
tp.push(t);
sleep(1);
}
}
int main()
{
thread t(publish,"thread_0");
t.join();//线程等待
return 0;
}