> 文档中心 > 线程池 - 分析与实现(一)

线程池 - 分析与实现(一)

线程池 - 分析与实现(一)

  • 思考
  • 线程池
    • 作用
    • 举个小例子
    • “池子”中都些什么?
    • 代码
  • 总结

思考

  • 线程池的作用?
  • 线程池的工作原理?
  • 线程池的API有哪些?具体怎么理解?

充电站
推荐一个零声学院免费公开课程,个人觉得老师讲得不错,分享给大家:Linux,Nginx,ZeroMQ,MySQL,Redis,fastdfs,MongoDB,ZK,流媒体,CDN,P2P,K8S,Docker,TCP/IP,协程,DPDK等技术内容,立即学习

线程池

作用

简述来讲,线程池的作用主要两个方面:
1)减少线程创建与销毁;
2) 异步解耦的作用。

稍微长篇的讲,其一就是对于线程的重用,线程的创建和销毁的开销是巨大的,而通过线程池的重用大大减少了这些不必要的开销,当然既然少了这么多消费内存的开销,则线程的执行速度起飞了。其二就是对于线程的管理,线程池可以提供定时、定期、单线程、并发数控制等功能。控制线程池的并发数可以有效的避免大量的线程池争夺CPU资源而造成堵塞。

举个小例子

着重强调异步解耦的作用,以写日志为例,如loginfo("------\n");,日志需要落盘,写入磁盘中。我们将日志“落盘”当成一个任务,把这个任务抛给线程池,对于应用程序而言,这样就可以大大提升“落盘”的效率。

“池子”中都些什么?

这里不得不有举个例子来说说了,把线程池看做银行营业厅,银行营业厅里有什么呢?有柜员、办业务的人、公示牌、等等。线程池类似这样的“银行营业厅”
在这里插入图片描述

1)柜员–>线程–>执行队列(很多的柜员);
2)办业务的人–>任务–>任务队列(很多办业务的人);
3)公式牌–>管理作用–>促使柜员与办业务的人有序进行。
这三项都具备各自的“属性”,后面代码中会介绍。

代码

代码实现
柜员–>线程–>执行队列

// 执行队列->双链表实现typedef struct NWORKER {pthread_t thread; //线程ID,即工号int terminate;//flag 终止标志struct NWORKQUEUE *workqueue; //线程池的对象struct NWORKER *prev;struct NWORKER *next;} nWorker;

办业务的人–>任务–>任务队列

// 任务队列->双链表实现typedef struct NJOB {void (*job_function)(struct NJOB *job); //回调函数void *user_data; //参数struct NJOB *prev;struct NJOB *next;} nJob;

线程池核心管理任务队列和执行队列有秩序进行的组件,不要将线程池理解为了连接池。

// 线程池typedef struct NTREADPOOL {struct NWORKER *workers; //多个柜员struct NJOB *waiting_jobs; //办业务的人pthread_mutex_t jobs_mtx; //公示牌->互斥锁pthread_cond_t jobs_cond; //公示牌->等待条件满足} nWorkQueue;

在这里插入图片描述
用宏定义实现队列的添加和删除

// ADD:在list中添加item(头插法)#define LL_ADD(item, list) do { \item->prev = NULL;\item->next = list;\list = item;\} while(0)
// REMOVE:在list中删除item#define LL_REMOVE(item, list) do {\if (item->prev != NULL) item->prev->next = item->next;\if (item->next != NULL) item->next->prev = item->prev;\if (list == item) list = item->next;\item->prev = item->next = NULL;\} while(0)

总结

    本文介绍了线程池用的作用,以形象的例子说明线程池的重要组成以及各个部分的代码实现。下篇将介绍线程池的API,以及对应的代码实现

后续更精彩
下半场: 线程池 - 分析与实现(二).