线程池
一堆线程进行任务处理,主要针对大量任务需要处理的场景,使用多执行流可以提高处理效率
如果一个任务到来就创建一个线程来处理这有很大缺点:
- 成本:总耗时=线程创建时间+任务处理时间+线程销毁时间,如果任务处理时间短,则大量时间被线程创建与销毁消耗了
- 风险:如果有大量线程进来,则在峰值压力下系统可能会有崩溃风险
思想:线程池其实是一堆创建好的线程和一个任务队列,有任务来了就抛入线程池中,分配一个线程进行处理
线程池中的线程与任务节点数量都有最大限制,避免资源消耗.
实现:
typedef void (*handler_t)(int data);
class ThreadTask{
private:
int _data;//要处理的数据
handler_t _handler;//处理数据的函数
public:
ThreadTask() {}
ThreadTask(int data, handler_t handler):_data(data),
_handler(handler){}
void Run(){
_handler(_data);
}
};
class BlockQueue
{
private:
std::queue<ThreadTask> _queue;
int _capacity;
pthread_mutex_t _mutex;
pthread_cond_t _cond_pro;
pthread_cond_t _cond_con;
public:
BlockQueue(int maxq = MAXQ):_capacity(maxq){
pthread_mutex_init(&_mutex, NULL);
pthread_cond_init(&_cond_pro, NULL);
pthread_cond_init(&_cond_con, NULL);
}
~BlockQueue() {
pthread_mutex_destroy(&_mutex);
pthread_cond_destroy(&_cond_pro);
pthread_cond_destroy(&_cond_con);
}
bool Push(const ThreadTask &data){
pthread_mutex_lock(&_mutex);
while(_queue.size() == _capacity) {
pthread_cond_wait(&_cond_pro, &_mutex);
}
_queue.push(data);
pthread_mutex_unlock(&_mutex);
pthread_cond_signal(&_cond_con);
return true;
}
bool Pop(ThreadTask *data) {
pthread_mutex_lock(&_mutex);
while(_queue.empty() == true) {
pthread_cond_wait(&_cond_con, &_mutex);
}
*data = _queue.front();
_queue.pop();
pthread_mutex_unlock(&_mutex);
pthread_cond_signal(&_cond_pro);
return true;
}
};
class Threadpool{
private:
int _max_thread;//线程最大数量
int _max_queue;//任务队列中节点最大数量
BlockQueue _queue;
public:
Threadpool(int max_thr=MAX_THREAD, int max_q=MAXQ):
_max_thread(max_thr),
_max_queue(max_q), _queue(max_q){
pthread_t tid;
int ret;
for (int i = 0; i < max_thr; i++) {
ret = pthread_create(&tid, NULL, thr_entry, this);
if (ret != 0) {
printf("thread create error\n");
exit(-1);
}
pthread_detach(tid);
}
}
static void *thr_entry(void *arg){
Threadpool *pool = (Threadpool*)arg;
while(1) {
ThreadTask task;
pool->_queue.Pop(&task);
task.Run();
}
}
bool TaskPush(const ThreadTask &task) {
_queue.Push(task);
}
};
单例模式
针对场景:一个类只能实例化一个对象,提供一个访问接口,也就是说一个资源在内存中只能有一份
目的:节约内存;防止数据二义;
具体实现
饿汉与懒汉模式
饿汉资源全部提前加载初始化完毕,用的时候直接用(以空间换时间)
- 构造函数私有化,无法在类外实例化对象
- 在类内实例化全局唯一对象,资源单独一份共享,运行前初始化,初始化过程不用考虑线程安全问题
懒汉:资源使用的时候再加载(用的比较多)
- 构造函数私有
- 在访问接口中加锁保护资源初始化加载过程
- 二次检测,防止锁冲突,提高效率
- 防止编译器过度优化,使用volatile修饰指针成员变量
//饿汉模式
class Singleton
{
public:
static Singleton* GetInstance()
{
return &_instance;
}
private:
Singleton(){};
Singleton(Singleton const&);
static Singleton _instance;//全局的唯一对象
};
//懒汉模式
class Singleton
{
public:
volatile static Singleton* GetInstance()
{
if (_instance == nullptr)
{
m_mutex.lock();
if (_instance == nullptr)
{
_instance = new Singleton();
}
m_mutex.unlock();
}
return _instance;
}
private:
Singleton() {};//构造函数私有
volatile static Singleton* _instance;//单例对象指针
static mutex m_mutex;//互斥锁
};
|