线程池的作用:和内存池一样,减少内核态与用户态之间的切换
用C++11新特性实现的超简版线程池:
#include<thread>
#include<mutex>
#include<condition_variable>
#include<vector>
#include<future>
#include<queue>
#include<iostream>
class ThreadPool {
public:
std::queue< std::function<void()> > task_queue;
std::vector<std::thread*> threads;
std::mutex mtx;
std::condition_variable cv;
bool isWork = true;
public:
ThreadPool(int size = 5) {
if (size <= 0) return;
for (int i = 0; i < size; ++i) {
threads.push_back( new std::thread(
[=] {
std::function<void()> task;
while (isWork) {
{
std::unique_lock<std::mutex> lock(mtx); //先抢到锁的线程获得锁,继续执行
/*
1. 线程有锁, 则会执行lambda判断
1.1 判断为假,交还锁,线程阻塞
1.2 判断为真,线程拿着锁,继续执行
2. 收到notify_one
2.1 没有线程wait,notify_one无用
2.2 有线程wait,且锁没有被使用,选一个线程,并把锁交给该线程,然后回到1
2.3 有线程wait,但是没有锁,则cv将会等到锁被交还的时候,才会选一个线程,并把锁交给该线程,然后回到1, 如果在等锁的过程中有线程A进入,则线程A会得到锁吗
3. 收到notify_all,但是没有锁,则cv将会等到锁被交还的时候,才会选一个线程,并把锁交给该线程,然后回到1
3.1.没有线程wait,notify_one无用
2.2 有线程wait,且锁没有被使用,选一个线程,并把锁交给该线程,然后回到1,
2.3 有线程wait,但是没有锁,则cv将会等到锁被交还的时候,才会选一个线程,并把锁交给该线程,然后回到1
3.3 循环2.2 2.3 直到所以notify之前wait的线程都拿到过锁
*/
cv.wait(lock, [this] { return !task_queue.empty(); });
if (task_queue.empty())
continue;
task = task_queue.front(); //获取任务
task_queue.pop();
} //作用域结束,交还锁
task(); //任务完成时可执行对象task占用的内存会自动回收
}
}
));
threads[i]->detach(); //启动
}
}
template<class F, class... P>
auto insertTask(F &&f, P&&... p)-> std::future<decltype( f(p...) )> {
using taskRetType = decltype( f(p...) ); //获取F的返回类型
auto pkt_task = std::make_shared< std::packaged_task<taskRetType()> >
( std::bind(std::forward<F>(f), std::forward<P>(p)...) );
std::future<taskRetType> ret = pkt_task->get_future(); //获取与任务关联的future
{ //进入临界区,将任务放入任务队列
std::unique_lock<std::mutex> lock(mtx);
task_queue.push( [pkt_task]{ (*pkt_task)(); } );
}
cv.notify_one();//唤醒被阻塞线程
return ret;
}
};
成员变量介绍:
名称 | 类型 | 作用 |
task_queue | std::queue< std::function<void()> > | 一个队列,队列的元素为一个可执行对象;该队列会被线程池中的所有线程访问,所以对他的读写要加上锁,写加锁是为了防止数据不一致,读加锁是为了防止同一任务被多个线程执行;同时也应注意在任务执行完成时释放掉可执行对象占用的内存 |
threads | std::vector<std::thread*> | 线程池 |
mtx | std::mutex | 互斥量,相当于一把锁 |
cv | std::condition_variable | 线程同步,唤醒或者沉睡线程 |