基于任务队列(TaskQueue)和线程组(thread_group),实现线程池,线程池中所有线程等待在任务队列上,循环执行:等待任务到来->获取到任务->执行任务。
ThreadPool继承自TaskExecutor,TaskExecutor又同时继承了ThreadLoadCounter和TaskExecutorInterface,所以线程池支持负载统计、同步以及异步执行任务
分析
class ThreadPool : public TaskExecutor {
public:
enum Priority {
PRIORITY_LOWEST = 0,
PRIORITY_LOW,
PRIORITY_NORMAL,
PRIORITY_HIGH,
PRIORITY_HIGHEST
};
private:
size_t _thread_num;
TaskQueue<Task::Ptr> _queue;
thread_group _thread_group;
Priority _priority;
};
start:创建并启动线程
void start() {
if (_thread_num <= 0) {
return;
}
size_t total = _thread_num - _thread_group.size();
for (size_t i = 0; i < total; ++i) {
_thread_group.create_thread(std::bind(&ThreadPool::run, this));
}
}
线程组中创建指定数量的线程,当线程组中线程数不足时,补齐缺少的。已经达指定数量时,该接口什么也不做。
等下我们再来看ThreadPool::run是个什么东西。
wait-等待线程组中所有线程退出
void wait() {
_thread_group.join_all();
}
shutdown-队列中所有任务执行完成后让线程退出
void shutdown() {
_queue.push_exit(_thread_num);
}
async-异步执行任务
如果运行同步执行,并且当前调用线程在线程组中,则同步执行任务。否则就放入队列中异步执行
using TaskIn = std::function<void()>;
using Ptr = std::shared_ptr<TaskCancelableImp>;
Task::Ptr async(TaskIn task, bool may_sync = true) override {
if (may_sync && _thread_group.is_this_thread_in()) {
task();
return nullptr;
}
auto ret = std::make_shared<Task>(std::move(task));
_queue.push_task(ret);
return ret;
}
async_first
与async的区别是,async将任务放在队尾,async-first将任务放在队首,确保优先执行。
Task::Ptr async_first(TaskIn task, bool may_sync = true) override {
if (may_sync && _thread_group.is_this_thread_in()) {
task();
return nullptr;
}
auto ret = std::make_shared<Task>(std::move(task));
_queue.push_task_first(ret);
return ret;
}
size:有多少个任务待执行
size_t size() {
return _queue.size();
}
shutdown:队列中所有任务执行完成后让线程退出
void shutdown() {
_queue.push_exit(_thread_num);
}
队列的push_task和push_task_first会插入任务并触发一次唤醒wait的操作,等待在队列上的线程此时会从队列中获取到任务并执行。
但是push_exit没有给队列插入任务,也会触发其参数指定的n次唤醒wait的操作,等待在队列上的线程被唤醒后,因为实际并没有插入任务,所以这n次是获取不到任务的,队列为空。
基于上述条件,实现了run函数的自动退出(获取任务失败时,退出线程),push_exit指定多唤醒的次数与线程组中线程数量一致,每唤醒一次,就有一个线程被退出,最终刚好让所有线程都退出。
调用shutdown之后,需要调用wait()函数等待线程全部退出。如析构函数中所示
析构函数
~ThreadPool() {
shutdown();
wait();
}
构造函数
- _thread_num :线程池中最多多少个线程
- _priority :线程优先级
- auto_run :必要的话,自动开启线程池
ThreadPool(int num = 1, Priority priority = PRIORITY_HIGHEST, bool auto_run = true) {
_thread_num = num;
_priority = priority;
if (auto_run) {
start();
}
}
run
ThreadPool::setPriority(_priority)
:设置当前函数,也就是run()
在系统中的优先级。具体稍后讲- 然后就进入了一个循环,循环中做了如下事情:
- 不断从任务队列中获取任务,并执行
- 如果任务队列为空了,就结束
ThreadPool::run
void run() {
ThreadPool::setPriority(_priority);
Task::Ptr task;
while (true) {
startSleep(); // ThreadLoadCounter::startSleep()
if (!_queue.get_task(task)) { //TaskQueue::get_task
//空任务,退出线程
break;
}
sleepWakeUp(); //ThreadLoadCounter::sleepWakeUp()
try {
(*task)(); // 执行任务
task = nullptr;
} catch (std::exception &ex) {
ErrorL << "ThreadPool执行任务捕获到异常:" << ex.what();
}
}
}
setPriority
static bool setPriority(Priority priority = PRIORITY_NORMAL, std::thread::native_handle_type threadId = 0) {
static int Min = sched_get_priority_min(SCHED_OTHER);
if (Min == -1) {
return false;
}
static int Max = sched_get_priority_max(SCHED_OTHER);
if (Max == -1) {
return false;
}
static int Priorities[] = {Min, Min + (Max - Min) / 4, Min + (Max - Min) / 2, Min + (Max - Min) * 3 / 4, Max};
if (threadId == 0) {
threadId = pthread_self();
}
struct sched_param params;
params.sched_priority = Priorities[priority];
return pthread_setschedparam(threadId, SCHED_OTHER, ¶ms) == 0;
}
由pthread_setschedparam(threadId, SCHED_OTHER, ¶ms)
实现