Linux服务器开发,线程池原理与实现

──────────────────────────────────────────────────────────────
┌————————————┐
│▉▉♥♥♥♥♥♥♥♥ 99

线程池原理与实现

  • 前言
  • 一、线程池究竟解决了什么问题?
    • API
  • 二、线程池的作用
  • 三、工作原理
  • 四、手写线程池
  • 五、对比nginx线程池
  • 六、总结

前言

一、线程池究竟解决了什么问题?

  • 可能第一感觉是线程池减少线程创建销毁,但是这是站在线程的角度去思考的。
  • 异步解耦的作用 主循环只做一个抛任务,写日志交给线程池,提高了程序运行效率。
    注重cpu的处理能力的时候才会去粘合,注重的任务的话还是不要粘合为好。

API

  • create、init
  • push_task 返回的结果对于业务来说作用不大
  • destroy、deinit
    锦上添花的api:task_count,free_thread。

二、线程池的作用

  • 线程池是管理任务队列和工作队列的管理组件。

三、工作原理

  • 线程池并非内存池那般,从池子里面取用完归还,而是线程之间争夺资源。
  • 通过线程池的入口函数去获取任务,循环往复,再取任务再循环。
  • 生产者消费者模型:任务队列是生产者,工作队列是消费者,加锁获取资源。
    Linux服务器开发,线程池原理与实现_第1张图片

四、手写线程池

  • 可以对任务进行区分,加优先级,更优秀的做法可以创建多个线程池对象。
  • 条件等待,进来时候解锁,出来加锁。
  • 当往任务队列中添加任务,应该先加锁锁住资源,中间发送条件变量的信号。
#define LL_ADD(item, list) do { 	\
	item->prev = NULL;				\
	item->next = list;				\
	if(list !< NULL) list *prev =item  \
	list = item;					\
} while(0)
  • 利用宏向链表中添加数据,这个感觉奇妙啊~
 while (1) {
		pthread_mutex_lock(&worker->workqueue->jobs_mtx);
		while (worker->workqueue->waiting_jobs == NULL) {
			if (worker->terminate) break;
			pthread_cond_wait(&worker->workqueue->jobs_cond, &worker->workqueue->jobs_mtx);
		}
		if (worker->terminate) {
			pthread_mutex_unlock(&worker->workqueue->jobs_mtx);
			break;}
		nJob *job = worker->workqueue->waiting_jobs;
		if (job != NULL) {
			LL_REMOVE(job, worker->workqueue->waiting_jobs);}
		pthread_mutex_unlock(&worker->workqueue->jobs_mtx);
		if (job == NULL) continue;
		job->job_function(job);
	}
  • 条件变量这块,是先解锁再加锁,King老师反复强调。不停的判断job为空,需要注意一下,担心万一被别的线程占用了怎么办。
    pthread_mutex_lock(&workqueue->jobs_mtx);
workqueue->workers = NULL;
workqueue->waiting_jobs = NULL;
pthread_cond_broadcast(&workqueue->jobs_cond);
pthread_mutex_unlock(&workqueue->jobs_mtx);
  • 通知等待着的线程,不折不扣的生产者,不过发送信号也需要加锁。防止竞争。

五、对比nginx线程池

我们的线程池为双链表,nginx的队列为什么使用二级指针。因为一级指针能指向struct ngx_thread_task_s的第一项ngx_thread_task_t *next的位置,这也正是ngx的巧妙之处。

六、总结

通过今天的学习,不仅学习到了有关线程池的知识,更重要的King老师讲述了学习的三个过程:1、逻辑想通;2、代码调通;3、对照学习。目测小生只是刚刚能做好第一步,接下来还是要付出更多的努力才能将这些知识驾驭娴熟。
这节课确实是比较轻松的,不过需要注意的是King老师在添加删除链表时使用的宏方法,这个也不是第一次见到了,希望能掌握好成为自己的东西。线程之间的条件等待也绝不是第一次听说,wait使得所有线程都爬在此处,等待任务队列中有数据,随时触发线程之前抢占资源。最后就是不停的判断job是否为空,因为担心被其他线程抢走。
在未来的时间里,我会利用C++11的std::thread函数从新改造这个线程池,希望达到异曲同工之妙。

你可能感兴趣的:(服务器,linux,java)