线程可以实现任务的并发执行,线程池的实现思路是在程序启动时一次性启动很多线程,在任务到来时,直接从池中取线程执行任务,这样可以节省创建线程的开销。
线程池的实现中,有几个关键点:
1,每个线程启动时,需要指定一个入口函数,此函数即线程将执行的函数。但是线程生成时,并不知道要执行什么任务,此时线程入口函数将怎么设置呢?答案就是使用函数指针。线程池中各个线程的入口函数一般是同一个函数,而此函数的参数是一个函数指针,而在入口函数中,执行函数指针所对应的函数,这样就可以实现预先创建线程,而不用指定具体执行的函数。
2,线程池的工作过程可以看做是一个生产者消费者问题,主线程是生产者,线程池的各个线程是消费者,主线程首先初始化线程池,然后往线程池的worker队列中add worker(加锁),在add之后,会通过条件变量激活阻塞中的线程池中的线程,一个线程被激活后,会从worker队列中取woker(函数指针和参数)(加锁),然后执行此函数,然后继续等待从队列中取新的worker
3,从上面流程可以看出,线程池主要组件包括
一个worker队列,比如可以是链表,也可以叫做任务队列,因为这个队列中的元素,其实是一个个的函数,或者叫带数据的函数
一个锁,和 一个条件变量,用于上述队列的add get 同步
若干个pthread_t 句柄
一个init 函数,初始化锁和条件变量,按照线程数目创建线程
一个线程创建时的入口函数,此函数是个死循环,从worker队列中取worker,然后执行
一个destory函数,用来释放线程,释放队列,注意释放前,需要将各个线程停止,一般先通过广播条件变量,让所有线程停止阻塞,通过共享的变量,得知要停,然后退出
4, 另外相关的数据结果还包括
worker: 一个函数指针和一个参数指针,为了行程链表,需要一个next指针
上面是所有线程共享一个任务队列,另外还有一种实现方式,是每个线程一个任务队列
实现的基本思路是
一个Thread类,包装了pthread_t ,主要方法为start(),start会生成新的thread,入口函数会调用本对象的纯虚函数,比如Run
继承Thread类的新类,可以通过重载Run方法,定制入口函数,还可以加入一些成员变量,比如本线程独享的任务队列,Run方法就是循环从队列中取任务,执行,取任务,执行。注意,Thread类中的pause,stop等方法,有可能不能真正影响其代表的线程,比如pause方法中如果调用 condition wait,只是阻塞的调用线程,而非本对象代表的线程。
基于此,再实现一个线程池,其实就是生成若干Thread 对象,然后依次调用start函数,如果想让线程池干活儿,可以直接通过往对应线程的任务队列中放入任务。此处的任务,即一个实现了Callable接口的对象,将callable对象放入线程专属的任务队列之前,线程会阻塞,等待队列非空,放入任务,会自动开始执行。