📖1. 线程池概念
线程池:一种线程使用模式,线程过多会带来调度开销,进而影响缓存局部性和整体性能. 而线程池维护着多个线程,等待着管理者分配可并发执行的任务. 这避免了在处理短时间任务时创建与销毁线程的代价,线程池不仅能保证内核的充分利用,还能防止过分调度,可用的线程数量应该取决于可用的并发处理器,处理器内核,内存,网络socket
数量.
线程池的应用场景:
- 需要大量的线程来完成任务,且任务完成的时间比较短,Web服务器完成网页请求这样的任务,使用线程池技术是非常合适的,因为单个任务小,而任务数量巨大,你可以想象一个热门网站的点击次数,但对于长时间的任务,线程池的任务就不明显了.
- 对性能要求苛刻的应用,比如要求服务器迅速响应客户请求.
- 接受突发性的大量请求,但不至于使服务器因此产生大量线程的应用,突发性大量客户请求,在没有线程池情况下,将产生大量线程,虽然理论上大多数操作系统线程数目最大值不是问题,短时间内产生大量线程可能使内存到达极限,出现错误.
线程池的示例:
- 创建固定数量线程池,循环从任务队列中获取任务对象.
- 获取到任务对象后,执行任务对象中的任务接口.
📖2. 线程池实现
#pragma once
#include<iostream>
#include<cassert>
#include<queue>
#include<pthread.h>
#include<sys/prctl.h>
#include "Log.hpp"
using namespace std;
int gThreadNum = 5;
template<class T>
class ThreadPool
{
public:
ThreadPool(int threadNum = gThreadNum)
: threadNum_(gThreadNum)
, isStart_(false)
{
assert(threadNum_ > 0);
pthread_mutex_init(&mutex_, nullptr);
pthread_cond_init(&cond_, nullptr);
}
~ThreadPool()
{
pthread_mutex_destroy(&mutex_);
pthread_cond_destroy(&cond_);
}
static void* threadRoutine(void* args)
{
pthread_detach(pthread_self());
ThreadPool<T>* tp = static_cast<ThreadPool<T>* >(args);
prctl(PR_SET_NAME, "follower");
while(1)
{
tp->lockQueue();
//如果没任务就wait
while(!tp->haveTask())
{
tp->waitForTask();
}
//这个任务被一个线程执行
T t = tp->pop();
tp->unlockQueue();
int one, two;
char oper;
t.get(&one, &two, &oper);
Log()<<"新线程完成计算任务: "<< one << oper << two << "=" << t.run() << "\n";
}
}
//调用start, 线程池开始工作
void start()
{
assert(!isStart_);
for(int i = 0; i < threadNum_; ++i)
{
pthread_t temp;
pthread_create(&temp, nullptr, threadRoutine, this);
}
isStart_ = true;
}
void push(const T& in)
{
lockQueue();
taskQueue_.push(in);
choiceThreadForHandler();
unlockQueue();
}
private:
void lockQueue() { pthread_mutex_lock(&mutex_); }
void unlockQueue() { pthread_mutex_unlock(&mutex_); }
bool haveTask() { return !taskQueue_.empty(); } //有无任务
void waitForTask() { pthread_cond_wait(&cond_, &mutex_); }
void choiceThreadForHandler() { pthread_cond_signal(&cond_); } //选择一个线程去处理
T pop()
{
T temp = taskQueue_.front();
taskQueue_.pop();
return temp;
}
private:
bool isStart_;
int threadNum_;
queue<T> taskQueue_; //任务队列
pthread_mutex_t mutex_; //互斥锁
pthread_cond_t cond_;
};
//测试线程池
#include "ThreadPool.hpp"
#include "Task.hpp"
#include "Log.hpp"
#include <ctime>
#include <unistd.h>
#include <sys/prctl.h>
int main()
{
prctl(PR_SET_NAME, "master");
const string operators = "+-*/";
ThreadPool<Task>* tp = new ThreadPool<Task>();
tp->start();
srand((unsigned long)time(nullptr) ^ getpid() ^ pthread_self());
//派发任务
while(true)
{
int one = rand() % 50;
int two = rand() % 10;
char oper = operators[rand() % operators.size()];
Log() << "主线程派发计算任务" << one << oper << two << "=?" << "\n";
Task t(one, two, oper);
tp->push(t);
sleep(1);
}
return 0;
}