线程池
一种线程使用模式。线程过多会带来调度开销,进而影响缓存局部性和整体性能。而线程池维护着多个线程,等待着监督管理者分配可并发执行的任务。这避免了在处理短时间任务时创建与销毁线程的代价。线程池不仅能够保证内核的充分利用,还能防止过分调度。可用线程数量应该取决于可用的并发处理器、处理器内核、内存、网络sockets等的数量。
A.降低资源消耗:通过重用已经创建的线程来降低线程创建和销毁的消耗
B.提高线程的可管理性:线程池可以统一管理、分配、调优和监控
C.程序性能更优:创建的线程越多性能越高
实现一个线程池
先封装一个待处理的数据和处理数据的函数 class Task
typedef void (*handler_t)(int data);
class Task {
private:
int _data;
handler_t _handler;
public:
void setdata(int data, handler_t func) {
_data = data;
_handler = func;
}
void run() {
_handler(_data);
}
};
void thr_handle(int data) {
srand(time(NULL));
int sec = rand() % 5;
printf("thr:%p--get data:%d--sleep:%d sec\n", pthread_self(), data, sec);
sleep(sec);
}
实现一个线程池:由一个线程安全的任务队列和多个线程组成
有一个问题需要注意的是:线程什么时候退出?
如果主函数退出的话,则可能有线程还没没有处理完就退了,所以需要所有线程全部退出后主线程才可以退出。
这时增加两个成员变量,一个记录正在处理任务的线程的个数,一个是状态标志位(区分线程被唤醒是否被退出函数唤醒的)
线程池收到退出请求,将退出标志位设置为true,判断是否还有线程运行,在去唤醒所有线程,如果有线程被唤醒说明,这个线程已经没有在处理任务,则将该线程退出。
class ThreadPool {
private:
int th_max;
std::queue<Task> _task_queue;
pthread_mutex_t mutex;
pthread_cond_t pro_cond;
pthread_cond_t con_cond;
int _cur_thr; //当前线程数
bool _quit_flag; //线程池中线程退出标志
private:
void QueueBlock() {
pthread_mutex_lock(&mutex);
}
void QueueUnBlock() {
pthread_mutex_unlock(&mutex);
}
void ConsumerWait() {
//线程陷入等待之前先判断一下用户是否要销毁线程池
if (_quit_flag == true) {
_cur_thr--;
pthread_mutex_unlock(&mutex);
printf("thread:%p exit\n", pthread_self());
pthread_exit(NULL);
}
pthread_cond_wait(&con_cond, &mutex);
}
void ConsumerWakeUp() {
pthread_cond_signal(&con_cond);
}
void ConsumerWakeUpAll() {
pthread_cond_broadcast(&con_cond);
}
bool QueueIsEmpty() {
return _task_queue.empty();
}
public:
ThreadPool(int max = THR_MAX) : th_max(max), _cur_thr(max) {
_quit_flag = false;
pthread_mutex_init(&mutex, NULL);
pthread_cond_init(&con_cond, NULL);
pthread_cond_init(&pro_cond, NULL);
}
~ThreadPool() {
pthread_mutex_destroy(&mutex);
pthread_cond_destroy(&con_cond);
pthread_cond_destroy(&pro_cond);
}
bool PoolInit() {
int ret;
pthread_t tid;
for (int i = 0; i < th_max; ++i) {
ret = pthread_create(&tid, NULL, thr_start, this);
if (ret != 0) {
std::cout << "pthread create error\n";
return false;
}
pthread_detach(tid);
}
return true;
}
bool TaskPush(Task &t) {
pthread_mutex_lock(&mutex);
_task_queue.push(t);
pthread_cond_signal(&con_cond);
pthread_mutex_unlock(&mutex);
return true;
}
bool TaskPop(Task &t) {
t = _task_queue.front();
_task_queue.pop();
return true;
}
//static原因:如果不是static,这个函数还有一个默认参数this,这个函数就不能做创建进程函数的参数了
static void* thr_start(void* arg) {
ThreadPool* pool = (ThreadPool*)arg;
while (1) {
pthread_mutex_lock(&pool->mutex);
while (pool->_task_queue.empty()) {
pool->ConsumerWait();
}
Task t;
pool->TaskPop(t);
pthread_mutex_unlock(&pool->mutex);
t.run();
}
return NULL;
}
//为了避免主函数退出,导致所有线程退出, 让所有线程处理完再退出
void PoolQuit() {
QueueBlock();
if (_quit_flag == false) {
_quit_flag = true;
}
QueueUnBlock();
while (_cur_thr > 0) {
ConsumerWakeUpAll();
usleep(1000);
}
}
};
int main() {
ThreadPool pool;
pool.PoolInit();
for (int i = 0; i < 10; ++i) {
Task* task = new Task();
task->setdata(i, thr_handle);
pool.TaskPush(*task);
}
pool.PoolQuit();
return 0;
}