线程池概述
1.线程池的原理
为什么需要线程池
- 并发的线程数目较多,假如每一个线程都只是执行一个时间很短的任务就结束了,那么这样频繁的创建线程就会大大降低系统的效率,因为频繁创建和销毁线程都需要时间。
线程池就是使得线程可以复用,一个线程执行完一个任务后并不销毁。线程池里的线程都是后台线程。如果某个线程在托管代码中空闲,那么线程池将插入另一个辅助线程来使所有处理器繁忙。如果线程池中的所有线程都繁忙,但队列中包含挂起的任务,那么线程池应该创建一个辅助线程但线程的总数不应超过最大值。超过最大值的线程需要排队。
线程池的组成
任务队列
存储需要处理的任务,由工作的线程来处理这些任务,线程池threadpool中就是存储这些待处理的任务。
生产者消费者模型:生产者线程往任务队列里放任务,消费者线程把任务从队列中取出去。
工作的线程
任务队列的消费者。它们不停地读取任务队列,从中取出任务并处理。
如果任务队列为空,工作的线程将被阻塞;如果阻塞后有新的任务,由生产者将阻塞解除,工作线程开始工作。
管理者线程
周期性地对任务队列中任务的数量以及处于忙碌状态的工作线程进行检测。
- 任务过多的时候,可以创建一些新的工作线程
- 任务过少时,可以销毁一些工作线程
2.项目介绍
相关函数介绍
首先需要介绍几个pthread.h
的库函数。pthread_create(pthread_t *restrict thread, const pthread_attr_t`` *restrict attr, void *(*start_routine)(void *),void *restrict arg)
:创建线程, start_rountine
作为线程起始执行函数,arg
是传进该函数的参数。
pthread_join(pthread_t thread, void **retval)
:等待 thread
线程结束,调用该函数的线程将被阻塞。
pthread_cond_wait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex)
: 在调用这个函数前,都要获取mutex
互斥锁。然后挂起该线程,阻塞的时候释放mutex
这把锁(避免死锁)。等到再被唤醒的时候,他又会重新获取mutex
这把锁。
pthread_signal(pthread_cond_t *cond)
:唤醒阻塞在cond
条件变量上的所有线程,通常配合上面的函数一起使用。
代码实现思路
- 存活线程:是等待执行任务的线程或者已经在执行任务的线程
- 忙碌线程:已经在执行任务的线程
- 需要创建一个管理者线程,传入一个函数指针
manage
,这个manage
函数是一个while
循环,它每隔一段时间就做一次检查,判断是否需要添加新的存活线程或者销毁存活线程。 - 创建多个存活线程,传入函数指针
worker
,同样,这个worker
函数也是一个while
循环,不断处理线程池中的待处理任务。在获取了线程池中的任务后,待处理任务的执行就是一个函数调用,函数完成后接着下一次的while
循环判断。