理解线程池
简单的来说,线程池的本质就是使用空间换取时间,例如一个程序本来就需要10个字节,但是它申请内存的时候申请了20个字节,为它以后使用,这样在下次使用的时候就不需要再次申请内存了,从而牺牲了空间节省了时间。(池化技术)
线程池优点
- 线程池避免了在处理短时间内任务的创建和销毁。
- 线程池不仅能够保证内核充分利用,还能防止过分调度。
线程池使用场景
- 需要大量的线程来完成任务,且需要完成的任务时间短。
- 对性能要求苛刻的应用,比如要求服务器迅速响应客户请求。
- 接受突发性的大量请求,但不至于使服务器因此产生大量线程的应用。
例如
像Web服务器完成网页请求这样的任务,使用线程池技术是非常合适的。因为单个任务小,而任务数量巨大,你可以想象一个热门网站的点击次数。
线程池代码实现
下面我们实现一个简单的线程池,线程池中提供了一个任务队列,以及若干个线程(多线程)。
- 线程池中,多个线程任务都是从任务当中拿
- 线程池对外提供一个Push接口,用于让外部线程能够将任务Push到任务队列当中。
线程池内逻辑实现,这里我们锁线程共享的变量放到构造器里头直接初始化,其中,我们还是用了队列来存线程数据,如果有线程进入,我们就会将其线程的操作方法放入队列中,当运行后,我们再将其取出
ThreadPool_V2.hpp
#pragma once
#include <iostream>
#include <vector>
#include <queue>
#include <pthread.h>
#include <unistd.h>
#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;
}
//创建线程时要执行的任务
//类内的成员包含this指针,如果加了static就没有了
static void* threadRoutine(void* args)
{
pthread_detach(pthread_self());
ThreadPool<T>* tp = static_cast<ThreadPool<T>*>(args);
while(1)
{
//检测有没有任务需要主要
// 1.检测队列中有没有存放任务
// 2.有:处理
// 3.没有:等待
// 细节:需要加锁处理
tp->lockQueue();
while(tp->isEmpty())
{
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& t)
{
lockQueue();
_tasks.push(t);
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;
};
多线程共同执行的方法为
Task.hpp
#pragma once
#include <iostream>
#include <string>
#include <unistd.h>
class Task
{
public:
Task()
{
}
Task(int x, int y, char op) : _x(x), _y(y), _op(op), _result(0), _exitCode(0)
{
}
void operator()()
{
switch (_op)
{
case '+':
_result = _x + _y;
break;
case '-':
_result = _x - _y;
break;
case '*':
_result = _x * _y;
break;
case '/':
{
if (_y == 0)
_exitCode = -1;
else
_result = _x / _y;
}
break;
case '%':
{
if (_y == 0)
_exitCode = -2;
else
_result = _x % _y;
}
break;
default:
break;
}
usleep(100000);
}
std::string formatArg()
{
return std::to_string(_x) + _op + std::to_string(_y) + "= ?";
}
std::string formatRes()
{
return std::to_string(_result) + "(" + std::to_string(_exitCode) + ")";
}
~Task()
{
}
private:
int _x;
int _y;
char _op;
int _result;
int _exitCode;
};
主函数,用于控制多线程
main.cc
//#include "ThreadPool_V1.hpp"
#include "ThreadPool_V2.hpp"
#include "Task.hpp"
#include <memory>
int main()
{
std::unique_ptr<ThreadPool<Task>> tp(new ThreadPool<Task>());//创建线程池
tp->start();
while(1)
{
//充当生产者,从网络中读取数据,构建成任务,推送给线程池
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);
tp->pushTask(t);
}
}