目录
线程池
线程池代码
单例模式
饿汉模式单例模式
懒汉模式单例模式
在前几期,我们已经学习了多线程的创建和控制,学习了多线程中的同步和互斥,学习了多线程中的条件变量和信号量,基于此我们实现了基于阻塞队列和基于环形队列的生产者和消费者模型。本期将在此基础上进一步拓展学习,学习线程池相关的内容。
线程池
在学习线程池之前,我们通过一个场景为大家引入。图示如下。
当我们用户在用户层使用malloc函数和new操作符进行内存空间的申请时,必须由操作系统在底层使用对应的系统调用接口进行内存的申请,具体步骤为,进程由用户态切换为内核态,然后在内核态通过对应的内存算法进行内存的申请。但不免有一种情况,用户频繁的申请大小为1MB的空间,操作系统在底层不断地使用内存算法申请小块空间,在这种情景下,频繁地使用内存置换算法申请小块空间的代价是非常大的,效率也非常的低。基于此我们事先会通过操作系统在底层通过内存算法申请一大块空间,这样用户在申请时,可以直接从操作系统事先申请好的空间中去申请,不用再让操作系统频繁地使用内存算法申请小块空间,大大提高了效率。所以,内存池也是类似的原理,最终为提高了代码的执行效率。
内存池: 提前准备好的线程,用来随时处理任务,我们就称作线程池。
线程池代码
创建一个可以处理多个任务的线程池。
ThreadPool.hpp
#pragma once
#include <queue>
#include <pthread.h>
#include <iostream>using namespace std;namespace threadpool
{const int g_num = 5;template <class T>class ThreadPool{public:ThreadPool(const int &num = g_num) : _num(num){pthread_mutex_init(&_mutex, nullptr);pthread_cond_init(&_cond, nullptr);}~ThreadPool(){pthread_mutex_destroy(&_mutex);pthread_cond_destroy(&_cond);}void Wait(){pthread_cond_wait(&_cond, &_mutex);}void Lock(){pthread_mutex_lock(&_mutex);}void Unlock(){pthread_mutex_unlock(&_mutex);}void Pop(T *out){*out = _task_queue.front();_task_queue.pop();}void Push(const T &data){Lock();_task_queue.push(data);Unlock();Wakeup();}void Wakeup(){pthread_cond_signal(&_cond);}static void *Rountine(void *args){// 线程分离,分线程退出时不用主线程去等待。pthread_detach(pthread_self());ThreadPool<T> *tp = (ThreadPool<T> *)args;while (true){tp->Lock();// 分线程去处理任务while (tp->_task_queue.empty()){tp->Wait();}T t;tp->Pop(&t);tp->Unlock();std::cout<<pthread_self() << "得到的数据为 " << t << std::endl;}}void InitThreadPool(){pthread_t tid;for (int i = 0; i < g_num; i++){pthread_create(&tid, nullptr, Rountine, (void *)this);}}private:// 存放任务的队列queue<T> _task_queue;// 表示线程池中线程的数目int _num;pthread_mutex_t _mutex;pthread_cond_t _cond;};}
test.cc
#include "ThreadPool.hpp"
#include <iostream>
#include <unistd.h>
#include <time.h>
using namespace std;
using namespace threadpool;int main()
{ThreadPool<int> tp;tp.InitThreadPool();// 随机数种子srand((long long)time(nullptr));while (true){int a=rand()%20;tp.Push(a);cout << "发送的数据为" << a << endl;sleep(1);}return 0;
}
运行结果如下。
由运行结果可知,运行结果符合预期。
单例模式
在学习单例模式之前,我们了解一下什么是设计模式,模式其实就是特定的场景给予特定的解决方案。在人类社会中,成熟的行业都会有成熟的设计模式。何为单例模式,单例模式其实就是一个类只允许实例化出一个对象的设计模式。
饿汉模式单例模式
饿汉就是,工资日结。
懒汉模式单例模式代码。
template <class T>
class SigDistance
{
private:static SigDistance<T> _t;public:static SigDistance<T> *GetDistance(){return &_t;}
};
懒汉模式单例模式
懒汉就是,工资月结。
template <class T>
class SigDistance
{
private:static SigDistance<T> *_t;
public:static SigDistance<T> *GetDistance(){if (_t == nullptr){_t=new SigDistance();}return _t;}
};SigDistance<T>* SigDistance<T>::_t = nullptr;
基于懒汉单例模式的线程池
线程池往往只有一个,所以我们把线程池类设计成了单例模式,代码如下。
Thread.hpp
#pragma once
#include <queue>
#include <pthread.h>
#include <iostream>using namespace std;namespace threadpool
{const int g_num = 5;template <class T>class ThreadPool{private:ThreadPool<T>(const int &num = g_num) : _num(num){pthread_mutex_init(&_mutex, nullptr);pthread_cond_init(&_cond, nullptr);}~ThreadPool<T>(){pthread_mutex_destroy(&_mutex);pthread_cond_destroy(&_cond);}ThreadPool<T>(const ThreadPool<T> &tp) = delete;ThreadPool<T> &operator=(const ThreadPool<T> &tp) = delete;void Wait(){pthread_cond_wait(&_cond, &_mutex);}void Lock(){pthread_mutex_lock(&_mutex);}void Unlock(){pthread_mutex_unlock(&_mutex);}public:void Pop(T *out){*out = _task_queue.front();_task_queue.pop();}void Push(const T &data){Lock();_task_queue.push(data);Unlock();Wakeup();}void Wakeup(){pthread_cond_signal(&_cond);}static ThreadPool<T> *GetDistance(){static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;if(_tp==nullptr){pthread_mutex_lock(&lock);if (_tp == nullptr){_tp = new ThreadPool<T>();}}_tp->InitThreadPool();pthread_mutex_unlock(&lock);return _tp;}static void *Rountine(void *args){// 线程分离,分线程退出时不用主线程去等待。pthread_detach(pthread_self());ThreadPool<T> *tp = (ThreadPool<T> *)args;while (true){tp->Lock();// 分线程去处理任务while (tp->_task_queue.empty()){tp->Wait();}T t;tp->Pop(&t);tp->Unlock();std::cout << pthread_self() << "得到的数据为 " << t << std::endl;}}void InitThreadPool(){pthread_t tid;for (int i = 0; i < g_num; i++){pthread_create(&tid, nullptr, Rountine, (void *)this);}}private:// 存放任务的队列queue<T> _task_queue;// 表示线程池中线程的数目int _num;static ThreadPool<T> *_tp;pthread_mutex_t _mutex;pthread_cond_t _cond;};template <class T>ThreadPool<T> *ThreadPool<T>::_tp = nullptr;
}
需要注意的是,静态成员变量需要再类外进行初始化。
test.cc
#include "ThreadPool.hpp"
#include <iostream>
#include <unistd.h>
#include <time.h>
using namespace std;
using namespace threadpool;int main()
{ThreadPool<int> *tp = ThreadPool<int>::GetDistance();// 随机数种子srand((long long)time(nullptr));while (true){int a = rand() % 20;tp->Push(a);cout << "发送的数据为" << a << endl;sleep(1);}return 0;
}
运行结果如下。
运行结果符合预期。
以上便是线程池以及单例模式的所有内容。
本期内容到此结束^_^