概念:
一种线程使用模式。线程过多会带来调度开销,进而影响缓存局部性和整体性能。而线程池维护着多个线程,等待着 监督管理者分配可并发执行的任务。这避免了在处理短时间任务时创建与销毁线程的代价。线程池不仅能够保证内核的充分利 用,还能防止过分调度。可用线程数量应该取决于可用的并发处理器、处理器内核、内存、网络sockets等的数量。 线程池的应用场景: 1. 需要大量的线程来完成任务,且完成任务的时间比较短。 WEB服务器完成网页请求这样的任务,使用线程池技 术是非常合适的。因为单个任务小,而任务数量巨大,你可以想象一个热门网站的点击次数。 但对于长时间的任务,比如一个 Telnet连接请求,线程池的优点就不明显了。因为Telnet会话时间比线程的创建时间大多了。 2. 对性能要求苛刻的应用,比如要求服务器迅速响应客户请求。 3. 接受突发性的大量请求,但不至于使服务器因此产生大量线程的应用。突发性大量客户请求,在没有线程池情 况下,将产生大量线程,虽然理论上大部分操作系统线程数目最大值不是问题,短时间内产生大量线程可能使内存到达极限, 出现错误。
threadPool.hpp
// 线程池类定义
#pragma once
#include <vector>
#include <queue>
#include <pthread.h>
#include <iostream>
#include "thread.hpp"
#include "mutex.hpp"
#include "task.hpp"
const int g_thread_num = 3;
// 这样不太合适,因为这样的话,除非把它设计为单例模式,否则所有线程池共用一个任务队列,锁,条件变量,显然是不行的。
// template <class T>
// class ThreadPool
// {
// public:
// // 构造函数
// ThreadPool(int num = g_thread_num)
// : thread_num_(num)
// {
// pthread_mutex_init(&mutex_, nullptr);
// pthread_cond_init(&cond_, nullptr);
// }
// ~ThreadPool()
// {
// pthread_mutex_destroy(&mutex_);
// pthread_cond_destroy(&cond_);
// }
// public:
// void run()
// {
// pthread_t tid;
// // 让所有线程执行起来,等待任务,执行任务
// for (int i = 0; i < thread_num_; ++i)
// {
// pthread_create(&tid, nullptr, routine, (void *)this);
// }
// }
// // 因为类成员函数,有一个隐藏的this指针,不能直接作为void* (*p)(void*)函数
// //因此设置为static成员函数,但是routine内部要访问锁和条件变量,以及任务队列,因此把它们设置为static数据成员。
// //但是,这样的话,所有线程池都使用一个锁,一个条件变量,一个任务队列,这无疑不是最佳方案。
// static void *routine(void *args) // 消费者pop任务,此处为线程。
// {
// ThreadPool *tp = (ThreadPool *)args;
// while (true)
// {
// pthread_mutex_lock(&mutex_);
// while (task_queue_.empty())
// pthread_cond_wait(&cond_, &mutex_); // 线程等待任务投放,并解锁
// T t;
// t = task_queue_.front();
// task_queue_.pop();
// std::cout << "线程 " <&