概述
1、一个线程 pool,所有线程阻塞等待唤醒(有任务时唤醒)
2、任务队列 queue,队列中添加任务后就唤醒线程,线程从队头取走任务执行,典型的生产者-消费者模型。
3、mutex对队列上锁, 保证队列任务添加和取走的同步性
4、当线程数不足时可以动态增加线程数量。
代码
threadpool.hpp头文件
#pragma once
#include <iostream>
#include<stdlib.h>
#include<thread>
#include<mutex>
#include<condition_variable>
#include<vector>
#include<functional>
#include<queue>
#include<atomic>
#define N 10 //默认初始化线程数量
#define THREADPOOL_MAX_NUM 500 //最大线程数量
using namespace std;
class ThreadPool {
public:
//自定义void()的函数类型
using Task = function<void()>;
size_t initnum;
//线程数组
vector<thread> _pool;
//任务队列
queue<Task> _tasks;
//互斥锁条件变量
mutex _mutex;
condition_variable _cond;
//线程池是否在工作
atomic<bool> _run;
//空闲线程数量
atomic<int> _idlThreadNum;
public:
ThreadPool(int cnt = N) :_run(true), _idlThreadNum(cnt)
{
addThread(cnt); //初始化线程池,线程池数量为cnt
}
~ThreadPool()
{
_run = false;
_cond.notify_all(); // 唤醒所有线程执行
for (thread& thrd : _pool) {
//thread.detach(); // 让线程“自生自灭”
if (thrd.joinable()) //线程还在执行任务中则等待
thrd.join(); // 等待任务结束, 前提:线程一定会执行完
}
}
public:
//向任务队列添加任务
void addTask(const Task& f)
{
if (_run) {
//保护共享资源
unique_lock<mutex>lk(_mutex);
//给队列中添加任务
_tasks.push(f);
cout << "---------Add a task---------" << endl;
//空闲线程不够时,增加线程
if (_idlThreadNum < 1 && _pool.size() < THREADPOOL_MAX_NUM)
{
addThread(1);
cout << "new thread" << endl;
}
//唤醒等待线程
_cond.notify_one();
}
}
//向线程池中增加线程
void addThread(int num)
{
for (; num > 0 && _pool.size() < THREADPOOL_MAX_NUM; num--) {
_pool.emplace_back(&ThreadPool::runTask, this); //emplace_back容器内部原地构造
}
}
void runTask()
{
//不断遍历队列,判断要是有任务的话,就执行
while (_run) {
Task task; // 获取一个待执行的 task
{
// unique_lock 相比 lock_guard 的好处是:可以随时 unlock() 和 lock()
unique_lock<mutex> lock(_mutex);
_cond.wait(lock, [this] {
return !_run || !_tasks.empty(); //会暂时解锁lock并等待唤醒
}); // wait 直到有 task
if (!_run && _tasks.empty())
return;
task = move(_tasks.front()); // 按先进先出从队列取一个 task
_tasks.pop();
}
_idlThreadNum--;
task();//执行任务
_idlThreadNum++;
}
}
};
测试程序
#include<iostream>
#include"threadpool.hpp"
using namespace std;
void func(int i) {
cout << "pthread_id=" << this_thread::get_id() << endl;
cout << "task id" << "------>" << i << endl;
this_thread::sleep_for(chrono::seconds(rand() % 5)); //模拟工作时长
}
int main()
{
srand(time(nullptr));
ThreadPool p(5);
int i = 0;
int num = 20;
while (num--) {
i++;
//调整线程之间cpu调度
this_thread::sleep_for(chrono::milliseconds(100));
auto task = bind(func, i);
p.addTask(task);
}
return 0;
}
测试结果: