线程池:一种线程使用模式。线程过多会带来调度开销,进而影响缓存局部性和整体性能。而线程池维护着多个线程,等待着监督管理者分配可并发执行的任务。这避免了在处理短时间任务时创建与销毁线程的代价。线程池不仅能够保证内核的充分利用,还能防止过分调度。可用线程数量应该取决于可用的并发处理器、处理器内核、内存、网络sockets等的数量。
#pragma once
#include
#include
#include
#include
#include
#include
#include "Task.hpp"
const static int N = 5;
template<class T>
class ThreadPool{
public:
ThreadPool(int num = N) : _num(num), _threads(num){
pthread_mutex_init(&_lock, nullptr);
pthread_cond_init(&_cond, nullptr);
}
void lockQueue(){
pthread_mutex_lock(&_lock);
}
void unlockQueue(){
pthread_mutex_unlock(&_lock);
}
void threadWait(){
pthread_cond_wait(&_cond, &_lock); // 阻塞等待一个条件变量
}
void threadWakeup(){
pthread_cond_signal(&_cond); // 唤醒至少一个阻塞在条件变量上的线程
}
bool isEmpty(){
return _tasks.empty();
}
T popTask(){
T t = _tasks.front();
_tasks.pop();
return t;
}
static void* threadRoutine(void* args){ // 静态的方法无法使用类内的成员
// 1. 检测有没有任务
// 2. 有:处理
// 3. 无:等待
// 细节:必定加锁
pthread_detach(pthread_self());
ThreadPool<T> *tp = static_cast<ThreadPool<T>*>(args);
while (true){
tp->lockQueue();
while (tp->isEmpty()){
// 等待,cond
tp->threadWait();
}
T t = tp->popTask(); // 将数据从公共区域拿到私有区域
tp->unlockQueue();
t(); // 处理任务不应该在临界区中
std::cout << "thread handler done, result: " << t.formatRes() << std::endl;
}
}
void start(){
for (int i = 0; i < _num; i++){
pthread_create(&_threads[i], nullptr, threadRoutine, this);
}
}
void pushTask(const T& in){
lockQueue();
_tasks.push(in);
threadWakeup();
unlockQueue();
}
~ThreadPool(){
pthread_mutex_destroy(&_lock);
pthread_cond_destroy(&_cond);
}
private:
std::vector<pthread_t> _threads;
int _num;
std::queue<T> _tasks; // 使用stl的自动扩容的特性
pthread_mutex_t _lock;
pthread_cond_t _cond;
};
在V1版本中我们使用的是Linux中的线程库,代码主要是编写的是手动充当生产者,读取数据构建成为任务,然后推送给线程池,从线程池中获取任务,多线程分配任务以及并行处理。在这个线程池类中首先将加锁解锁以及条件变量相关的函数进行封装,对条件变量和互斥锁进行初始化设置,然后是创建线程用于处理任务,在此处由于类中的方法都有着隐藏的指针this因此需要将线程运行函数声明为静态函数,进程执行函数的时候首先判断是否有任务存在于任务队列中,没有的话就进行等待,若是有任务就将任务拿到自己的执行流中进行处理。
在这个版本中,我们将线程和互斥锁进行封装。将线程进行封装,使用vector来对线程进行管理
class Thread{
public:
typedef enum{
NEW = 0,
RUNNING,
EXITED
} ThreadStatus;
typedef void (*func_t)(void *);
public:
Thread(int num, func_t func, void *args) : _tid(0), _status(NEW), _func(func), _args(args){
char name[128];
snprintf(name, sizeof(name), "thread-%d", num);
_name = name;
}
int status() { return _status; }
std::string threadname() { return _name; }
pthread_t threadid(){
if (_status == RUNNING)
return _tid;
else{
return 0;
}
}
static void *runHelper(void *args){
Thread *ts = (Thread*)args; // 就拿到了当前对象
// _func(_args);
(*ts)();
return nullptr;
}
void operator ()() { //仿函数
if(_func != nullptr) _func(_args);
}
void run(){
int n = pthread_create(&_tid, nullptr, runHelper, this);
if(n != 0) exit(1);
_status = RUNNING;
}
void join(){
int n = pthread_join(_tid, nullptr);
if(n != 0){
std::cerr << "main thread join thread " << _name << " error" << std::endl;
return;
}
_status = EXITED;
}
~Thread() {}
private:
pthread_t _tid;
std::string _name;
func_t _func; // 线程未来要执行的回调
void *_args;
ThreadStatus _status;
};
下面就是使用封装的线程类来进行线程池的代码编写
// ...
template <class T>
class ThreadPool
{
public:
// ...
pthread_mutex_t* getLock(){
return &_lock;
}
static void threadRoutine(void *args){
// pthread_detach(pthread_self());
ThreadPool<T> *tp = static_cast<ThreadPool<T> *>(args);
while (true){
T t;
{ // 将加锁使用域进行隔离,能够进行自动的析构
LockGuard lockguard(tp->getLock()); // 填入的是锁的地址
while (tp->isEmpty())
{
tp->threadWait();
}
t = tp->popTask(); // 从公共区域拿到私有区域
}
// for test
t();
std::cout << "thread handler done, result: " << t.formatRes() << std::endl;
}
}
void init(){
for (int i = 0; i < _num; i++){
_threads.push_back(Thread(i, threadRoutine, this));
}
}
void start(){
for (auto &t : _threads){
t.run();
}
}
void check(){
for (auto &t : _threads){
std::cout << t.threadname() << " running..." << std::endl;
}
}
void pushTask(const T &t){
LockGuard lockguard(&_lock);
_tasks.push(t);
threadWakeup();
}
~ThreadPool(){
for (auto &t : _threads){
t.join();
}
pthread_mutex_destroy(&_lock);
pthread_cond_destroy(&_cond);
}
};
// main.cc
#include
// #include "ThreadPool_V1.hpp"
#include "ThreadPool_V2.hpp"
int main(){
std::unique_ptr<ThreadPool<Task>> tp(new ThreadPool<Task>(5));
tp->init();
tp->start();
tp->check();
while (true){
int x, y;
char op;
std::cout << "please Enter x> ";
std::cin >> x;
std::cout << "please Enter y> ";
std::cin >> y;
std::cout << "please Enter op(+-*/%)> ";
std::cin >> op;
Task t(x, y, op);
// 充当生产者, 从网络中读取数据,构建成为任务,推送给线程池
sleep(1);
tp->pushTask(t);
}
}