目录
1.什么是线程池,线程池的优势
创建一个线程,就是要这个线程去完成某种任务的。
池化技术就是,提前创建一批线程,有任务这一批线程就会执行。而不是有任务的时候在去创建线程。
池化技术有着更高的效率,因为线程都是提前创建好的,直接执行任务。
2.懒汉和饿汉模式
懒汉和饿汉模式是一种设计模式
懒汉模式:
例:进程需要一块内存资源,什么时候真正用到了这块内存时,我在去创建而不是提前创建。
这种模式的优点就是,启动的更快,程序启动时,数据要加载到内存,懒汉就是延时加载,用的时候在加载。
3.单例模式
就是某一些类,就应该只有一个对象,不应该有多个。
线程池就是这样的,创建两个线程池也没有意义,可以多创建几个线程。
实现方法
将类的构造函数进行私有,这样就无法在创建对象了。
在类中提供一个共有的静态方法,这个方法可以初始化和获取线程池。
4.日志系统
这个没什么难度,就是字符串的拼接,可能需要注意的就是可变参数的使用。
log.hpp
cpp
#ifndef __LOG_HPP__
#define __LOG_HPP__
#include <iostream>
#include <string>
#include <time.h>
#include <pthread.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdarg.h>
#include <fstream>
// 日志等级
enum loglevel
{
Debug = 0,
Info,
Warning,
Error,
FATAL,
};
namespace lg
{
bool isSave = false; //是否保存到文件
std::string savefile = "log.txt";//保存的文件名
std::string LeveltoString(int level) //将日志等级转化为字符串
{
switch (level)
{
case Debug:
return "Debug";
case Info:
return "Info";
case Warning:
return "Warning";
case Error:
return "Error";
case FATAL:
return "FATAL";
default:
return "Unknown";
}
}
std::string TimetoString() //将时间转化为字符串
{
time_t cur_time = time(nullptr);
tm *formattime = localtime(&cur_time);
return std::string(std::to_string(formattime->tm_year + 1900) + "/" + std::to_string(formattime->tm_mon + 1) + "/" + std::to_string(formattime->tm_mday) + " " + std::to_string(formattime->tm_hour + 1) + ":" + std::to_string(formattime->tm_min + 1));
}
std::string PidtoString()//将pid转化为字符串
{
return std::to_string(getpid());
}
void SavetoFile(std::string &message)//保存到文件
{
std::ofstream out(savefile, std::ios::app);
if (!out.is_open())
{
return;
}
out << message << std::endl;
out.close();
}
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
// 日志的格式: 日志等级 + 日志时间 + 代码文件名 + 行数 + 日志内容
void LogMessage(std::string filename, int linenum, int level, const char *formate, ...)
{
std::string levelstring = LeveltoString(level);
std::string timestring = TimetoString();
std::string pidstring = PidtoString();
//是对可变参数的解析
char buffer[1024];
va_list ap;
va_start(ap, formate);
vsnprintf(buffer, sizeof(buffer), formate, ap);
va_end(ap);
std::string contentstring = move(std::string(buffer));
std::string message = "[" + levelstring + "]" + "[" + timestring + "]" + "[" + filename + "]" + "[" + std::to_string(linenum) + "]" + "[" + pidstring + "]" + "[" + contentstring + "]";
if (!isSave)
{
pthread_mutex_lock(&mutex);
std::cout << message << std::endl;
pthread_mutex_unlock(&mutex);
}
else
{
SavetoFile(message);
}
}
#define Log(level, format, ...) \
do \
{ \
LogMessage(__FILE__, __LINE__, level, format, ##__VA_ARGS__); \
} while (0)
#define save() \
do \
{ \
isSave = true; \
} while (0);
#define print() \
do \
{ \
isSave = false; \
} while (0);
}
#endif
5.线程池
threadpool.hpp
cpp
#ifndef __THREADPOOL__
#define __THREADPOOL__
#include <iostream>
#include <pthread.h>
#include <thread>
#include <unistd.h>
#include <queue>
#include <semaphore.h>
#include "log.hpp"
#include <functional>
// 创建出一批线程,从任务队列里拿任务
namespace mtp
{
using namespace lg;
using namespace std::placeholders;
int _default = 3;
template <class T>
class threadpool
{
private:
threadpool(int threadnum = _default)
: _threadnum(threadnum)
{
pthread_mutex_init(&_mutex, nullptr);
pthread_cond_init(&_cond, nullptr);
Log(Info, "Construct threadpool");
}
// 线程的回调方法
void handlertask(std::string name)
{
while (true)
{
pthread_mutex_lock(&_mutex);
// 线程池运行 任务队列为空时
while (_isrunning && _taskqueue.empty())
{
_waitnum++;
pthread_cond_wait(&_cond, &_mutex);
_waitnum--;
}
// 线程池不运行 任务队列为空
if (!_isrunning && _taskqueue.empty())
{
pthread_mutex_unlock(&_mutex);
break;
}
// 线程池运行 队列不为空
// 线程池不运行 队列不为空
T t = _taskqueue.front();
_taskqueue.pop();
pthread_mutex_unlock(&_mutex);
t(name); // 执行任务
// std::cout<<"handler" << t <<std::endl;
}
}
// 创建线程
void Init()
{
for (int i = 0; i < _threadnum; i++)
{
std::string name = "thread" + std::to_string(i);
_threads.emplace_back(std::bind(&threadpool::handlertask, this, _1), name);
Log(Info, "create %s", name.c_str());
}
}
~threadpool()
{
pthread_mutex_destroy(&_mutex);
pthread_cond_destroy(&_cond);
Log(Info, "threadpool destory");
}
// 禁止拷贝
threadpool<T> &operator=(const threadpool<T> &) = delete;
threadpool(const threadpool<T> &) = delete;
public:
// 执行单例模式
static threadpool<T>* getInstance()
{
if (_instance == nullptr)//加上这个if语句,如果是获取线程池,就不用获取锁了
{
// 初始化线程池
pthread_mutex_lock(&_lock);
//只有第一次线程创建时才会进,无论创建还是获取都要返回 一个线程池的指针
if (_instance == nullptr)
{
_instance = new threadpool<T>;
_instance->Init();
Log(Info, "Init threadpool");
}
pthread_mutex_unlock(&_lock);
}
Log(Info, "get threadpool");
return _instance;
}
void stop()
{
pthread_mutex_lock(&_mutex);
_isrunning = false;
pthread_mutex_unlock(&_mutex);
pthread_cond_broadcast(&_cond);
}
void waitall()
{
for (auto &thread : _threads)
{
thread.join();
}
Log(Info, "Wait Sucess");
}
void enqueue(T t)
{
pthread_mutex_lock(&_mutex);
if (_isrunning)
{
_taskqueue.push(t);
Log(Info, "push task sucess");
if (_waitnum > 0)
{
pthread_cond_signal(&_cond);
}
}
pthread_mutex_unlock(&_mutex);
}
private:
int _threadnum;
std::vector<std::thread> _threads;
std::queue<T> _taskqueue; // 任务队列
pthread_mutex_t _mutex;
pthread_cond_t _cond;
bool _isrunning = true; // 是否运行
int _waitnum = 0; // d等待的线程数
// 添加单例模式
static threadpool<T> *_instance;
static pthread_mutex_t _lock; // 为了保证单例模式的线程安全
};
template <class T>
threadpool<T> *threadpool<T>::_instance = nullptr;
template <class T>
pthread_mutex_t threadpool<T>::_lock = PTHREAD_MUTEX_INITIALIZER;
}
#endif
Task.hpp
cpp
#ifndef __task_HPP__
#define __task_HPP__
#include<string>
#include<stdlib.h>
#include<time.h>
#include<iostream>
class Task
{
public:
Task(std::string taskname)
:_taskname(taskname)
{}
void operator()(std::string name)
{
sleep(1);
std::cout << name <<"Excute "<< _taskname << std::endl;
}
private:
std::string _taskname;
};
#endif