线程池基础知识
线程池主要解决线程频繁创建销毁时资源浪费问题。
例如:
T1为线程创建实际
T2为线程运行任务时间
T3为线程销毁时间
总时间T = T1 + T2 + T3
如果T1+T3 在 T 中的总时间占比比较大,那么就可以考虑使用线程池进行优化,减少资源浪费。
线程池一般包含以下几个部分:
- 线程列表
- 任务队列
- 定时器
利用c++一些新特性可以很方便的写出一个简单的线程池
c++11 thread
stl::thread 是c++ 11新加入的特性。在c++ 11 之前则是使用pthread。不过个人倒是没怎么用过pthread,学的时候就直接上的thread。pthread倒是在学校教材上比较常见。
详细可以参考std::thread
mutex 与 unique_lock
mutex中文为互斥量。对,就是那个操作系统里天天考的那个。
使用方式为上锁和解锁,不过一般使用unique_lock或者lock_guard来进行操作。
两者皆为构造时上锁,析构时解锁。利用这个特点就可以利用作用域进行解锁操作。
{
unique_lock<mutex> lock(_lock);
// to do
}
当to do后,离开括号作用域时,锁会被自动解锁。
condition_variable
condition_variable同样是c++ 11新加入的。中文名为条件变量。condition_variable需要配合mutex,unique_lock或者lock_gard进行使用。
详细的可以参考condition_variable
实现
参考了ThreadPool,不过说实话大佬的代码只看懂了构造和析构部分,入队操作那里依旧是云里雾里,半懂不懂。
以下是我自己的实现,同时也放到我的github上了。Tiny Http Server
// threadpool.h
#ifndef __THREADPOOL_H__
#define __THREADPOOL_H__
#include<vector>
#include<deque>
#include<mutex>
#include<condition_variable>
#include<functional>
#include<thread>
class ThreadPool{
public:
using Function = std::function<void()>;
ThreadPool(int maxWork);
~ThreadPool();
void joinJob(Function job); //bind封装函数参数
private:
std::vector<std::thread> _worker;
std::deque<Function> _jobs;
std::mutex _lock;
std::condition_variable _cond;
bool _stop;
};
#endif
//threadpool.cpp
#include "threadpool.h"
ThreadPool::ThreadPool(int maxWork):_stop(false){
maxWork <=0 ? maxWork = 1 : maxWork;
for(int i=0 ; i < maxWork ; ++i){
_worker.emplace_back([this](){
for(;;){
Function job;
{
std::unique_lock<std::mutex> lock(_lock); //构造加锁,系构解锁 RAII
while(!_stop && _jobs.empty())
_cond.wait(lock); //不满足则解锁,阻塞。防止假唤醒需要while判断
if(_stop && _jobs.empty())
return;
job = _jobs.front();
_jobs.pop_front();
}
job();
}
});
}
}
ThreadPool::~ThreadPool(){
{
std::unique_lock<std::mutex> lock(_lock); //上锁
_stop = true;
}
_cond.notify_all();
for(auto &job : _worker)
job.join();
}
void ThreadPool::joinJob(Function job){
{
std::unique_lock<std::mutex> lock(_lock);
_jobs.push_back(job);
}
_cond.notify_one();
}