1. /*
  2. 线程池组成:
  3. 1、管理者线程:创建并管理线程,包括添加、删除、销毁线程,添加新任务
  4. 2、工作线程:线程池中的线程,执行管理者分配的任务
  5. 3、任务接口:任务要实现的接口,供工作线程调用
  6. 4、任务队列:存放没有处理的任务,缓冲作用
  7. */
  8.  
  9. #include <stdlib.h>
  10. #include <pthread.h>
  11. #include <unistd.h>
  12. #include <assert.h>
  13. #include <stdio.h>
  14. #include <string.h>
  15. #include <signal.h>
  16. #include <errno.h>
  17. #include "threadpool.h"
  18.  
  19. #define DEFAULT_TIME 10 /*10s检测一次*/
  20. #define MIN_WAIT_TASK_NUM 10 /*如果queue_size > MIN_WAIT_TASK_NUM 添加新的线程到线程池*/
  21. #define DEFAULT_THREAD_VARY 10 /*每次创建和销毁线程的个数*/
  22. #define true 1
  23. #define false 0
  24.  
  25. //任务接口
  26. typedef struct {
  27. void *(*function)(void *); /* 函数指针,回调函数 */
  28. void *arg; /* 上面函数的参数 */
  29. } threadpool_task_t; /* 各子线程任务结构体 */
  30.  
  31. /* 描述线程池相关信息 */
  32. struct threadpool_t {
  33. pthread_mutex_t lock; /* 用于锁住本结构体 */
  34. pthread_mutex_t thread_counter; /* 记录忙状态线程个数de琐 -- busy_thr_num */
  35. pthread_cond_t queue_not_full; /* 当任务队列满时,添加任务的线程阻塞,等待此条件变量 */
  36. pthread_cond_t queue_not_empty; /* 任务队列里不为空时,通知等待任务的线程 */
  37.  
  38. pthread_t *threads; /* 存放线程池中每个线程的tid。数组 */
  39. pthread_t adjust_tid; /* 存管理线程tid */
  40. threadpool_task_t *task_queue; /* 任务队列 */
  41.  
  42. int min_thr_num; /* 线程池最小线程数 */
  43. int max_thr_num; /* 线程池最大线程数 */
  44. int live_thr_num; /* 当前存活线程个数 */
  45. int busy_thr_num; /* 忙状态线程个数 */
  46. int wait_exit_thr_num; /* 要销毁的线程个数 */
  47.  
  48. int queue_front; /* task_queue队头下标 */
  49. int queue_rear; /* task_queue队尾下标 */
  50. int queue_size; /* task_queue队中实际任务数 */
  51. int queue_max_size; /* task_queue队列可容纳任务数上限 */
  52.  
  53. int shutdown; /* 标志位,线程池使用状态,true或false */
  54. };
  55.  
  56. /**
  57. * @function void *threadpool_thread(void *threadpool)
  58. * @desc the worker thread
  59. * @param threadpool the pool which own the thread
  60. */
  61. void *threadpool_thread(void *threadpool);
  62.  
  63. /**
  64. * @function void *adjust_thread(void *threadpool);
  65. * @desc manager thread
  66. * @param threadpool the threadpool
  67. */
  68. void *adjust_thread(void *threadpool);
  69.  
  70. /**
  71. * check a thread is alive
  72. */
  73. int is_thread_alive(pthread_t tid);
  74. int threadpool_free(threadpool_t *pool);
  75.  
  76. //创建线程池
  77. threadpool_t *threadpool_create(int min_thr_num, int max_thr_num, int queue_max_size)
  78. {
  79. int i;
  80. threadpool_t *pool = NULL;
  81. do {
  82. if((pool = (threadpool_t *)malloc(sizeof(threadpool_t))) == NULL) {
  83. printf("malloc threadpool fail");
  84. break;/*跳出do while*/
  85. }
  86.  
  87. pool->min_thr_num = min_thr_num;
  88. pool->max_thr_num = max_thr_num;
  89. pool->busy_thr_num = ;
  90. pool->live_thr_num = min_thr_num; /* 活着的线程数 初值=最小线程数 */
  91. pool->queue_size = ; /* 有0个产品 */
  92. pool->queue_max_size = queue_max_size;
  93. pool->queue_front = ;
  94. pool->queue_rear = ;
  95. pool->shutdown = false; /* 不关闭线程池 */
  96.  
  97. /* 根据最大线程上限数, 给工作线程数组开辟空间, 并清零 */
  98. pool->threads = (pthread_t *)malloc(sizeof(pthread_t)*max_thr_num);
  99. if (pool->threads == NULL) {
  100. printf("malloc threads fail");
  101. break;
  102. }
  103. memset(pool->threads, , sizeof(pthread_t)*max_thr_num);
  104.  
  105. /* 队列开辟空间 */
  106. pool->task_queue = (threadpool_task_t *)malloc(sizeof(threadpool_task_t)*queue_max_size);
  107. if (pool->task_queue == NULL) {
  108. printf("malloc task_queue fail");
  109. break;
  110. }
  111.  
  112. /* 初始化互斥琐、条件变量 */
  113. if (pthread_mutex_init(&(pool->lock), NULL) !=
  114. || pthread_mutex_init(&(pool->thread_counter), NULL) !=
  115. || pthread_cond_init(&(pool->queue_not_empty), NULL) !=
  116. || pthread_cond_init(&(pool->queue_not_full), NULL) != )
  117. {
  118. printf("init the lock or cond fail");
  119. break;
  120. }
  121.  
  122. /* 启动 min_thr_num 个 work thread */
  123. for (i = ; i < min_thr_num; i++) {
  124. pthread_create(&(pool->threads[i]), NULL, threadpool_thread, (void *)pool);/*pool指向当前线程池*/
  125. printf("start thread 0x%x...\n", (unsigned int)pool->threads[i]);
  126. }
  127. pthread_create(&(pool->adjust_tid), NULL, adjust_thread, (void *)pool);/* 启动管理者线程 */
  128.  
  129. return pool;
  130.  
  131. } while ();
  132.  
  133. threadpool_free(pool); /* 前面代码调用失败时,释放poll存储空间 */
  134.  
  135. return NULL;
  136. }
  137.  
  138. /* 向线程池中 添加一个任务 */
  139. int threadpool_add(threadpool_t *pool, void*(*function)(void *arg), void *arg)
  140. {
  141. pthread_mutex_lock(&(pool->lock));
  142.  
  143. /* ==为真,队列已经满, 调wait阻塞 */
  144. while ((pool->queue_size == pool->queue_max_size) && (!pool->shutdown)) {
  145. pthread_cond_wait(&(pool->queue_not_full), &(pool->lock));
  146. }
  147. if (pool->shutdown) {
  148. pthread_mutex_unlock(&(pool->lock));
  149. }
  150.  
  151. /* 清空 工作线程 调用的回调函数 的参数arg */
  152. if (pool->task_queue[pool->queue_rear].arg != NULL) {
  153. free(pool->task_queue[pool->queue_rear].arg);
  154. pool->task_queue[pool->queue_rear].arg = NULL;
  155. }
  156. /*添加任务到任务队列里*/
  157. pool->task_queue[pool->queue_rear].function = function;
  158. pool->task_queue[pool->queue_rear].arg = arg;
  159. pool->queue_rear = (pool->queue_rear + ) % pool->queue_max_size; /* 队尾指针移动, 模拟环形 */
  160. pool->queue_size++;
  161.  
  162. /*添加完任务后,队列不为空,唤醒线程池中 等待处理任务的线程*/
  163. //生产者消费者模型
  164. pthread_cond_signal(&(pool->queue_not_empty));
  165. pthread_mutex_unlock(&(pool->lock));
  166.  
  167. return ;
  168. }
  169.  
  170. /* 线程池中各个工作线程 */
  171. void *threadpool_thread(void *threadpool)
  172. {
  173. threadpool_t *pool = (threadpool_t *)threadpool;
  174. threadpool_task_t task;
  175.  
  176. while (true) {
  177. /* Lock must be taken to wait on conditional variable */
  178. /*刚创建出线程,等待任务队列里有任务,否则阻塞等待任务队列里有任务后再唤醒接收任务*/
  179. pthread_mutex_lock(&(pool->lock));
  180.  
  181. /*queue_size == 0 说明没有任务,调 wait 阻塞在条件变量上, 若有任务,跳过该while*/
  182. while ((pool->queue_size == ) && (!pool->shutdown)) {
  183. printf("thread 0x%x is waiting\n", (unsigned int)pthread_self());
  184. pthread_cond_wait(&(pool->queue_not_empty), &(pool->lock));
  185.  
  186. /*清除指定数目的空闲线程,如果要结束的线程个数大于0,结束线程*/
  187. if (pool->wait_exit_thr_num > ) {
  188. pool->wait_exit_thr_num--;
  189.  
  190. /*如果线程池里线程个数大于最小值时可以结束当前线程*/
  191. if (pool->live_thr_num > pool->min_thr_num) {
  192. printf("thread 0x%x is exiting\n", (unsigned int)pthread_self());
  193. pool->live_thr_num--;
  194. pthread_mutex_unlock(&(pool->lock));
  195. pthread_exit(NULL);
  196. }
  197. }
  198. }
  199.  
  200. /*如果指定了true,要关闭线程池里的每个线程,自行退出处理*/
  201. if (pool->shutdown) {
  202. pthread_mutex_unlock(&(pool->lock));
  203. printf("thread 0x%x is exiting\n", (unsigned int)pthread_self());
  204. pthread_exit(NULL); /* 线程自行结束 */
  205. }
  206.  
  207. /*从任务队列里获取任务, 是一个出队操作*/
  208. task.function = pool->task_queue[pool->queue_front].function;
  209. task.arg = pool->task_queue[pool->queue_front].arg;
  210.  
  211. pool->queue_front = (pool->queue_front + ) % pool->queue_max_size; /* 出队,模拟环形队列 */
  212. pool->queue_size--;
  213.  
  214. /*通知可以有新的任务添加进来*/
  215. pthread_cond_broadcast(&(pool->queue_not_full));
  216.  
  217. /*任务取出后,立即将 线程池琐 释放*/
  218. pthread_mutex_unlock(&(pool->lock));
  219.  
  220. /*执行任务*/
  221. printf("thread 0x%x start working\n", (unsigned int)pthread_self());
  222. pthread_mutex_lock(&(pool->thread_counter)); /*忙状态线程数变量琐*/
  223. pool->busy_thr_num++; /*忙状态线程数+1*/
  224. pthread_mutex_unlock(&(pool->thread_counter));
  225. (*(task.function))(task.arg); /*执行回调函数任务*/
  226. //task.function(task.arg); /*执行回调函数任务*/
  227.  
  228. /*任务结束处理*/
  229. printf("thread 0x%x end working\n", (unsigned int)pthread_self());
  230. pthread_mutex_lock(&(pool->thread_counter));
  231. pool->busy_thr_num--; /*处理掉一个任务,忙状态数线程数-1*/
  232. pthread_mutex_unlock(&(pool->thread_counter));
  233. }
  234.  
  235. pthread_exit(NULL);
  236. }
  237.  
  238. /* 管理线程 */
  239. void *adjust_thread(void *threadpool)
  240. {
  241. int i;
  242. threadpool_t *pool = (threadpool_t *)threadpool;
  243. while (!pool->shutdown) {
  244.  
  245. sleep(DEFAULT_TIME); /*定时 对线程池管理*/
  246.  
  247. pthread_mutex_lock(&(pool->lock));
  248. int queue_size = pool->queue_size; /* 关注 任务数 */
  249. int live_thr_num = pool->live_thr_num; /* 存活 线程数 */
  250. pthread_mutex_unlock(&(pool->lock));
  251.  
  252. pthread_mutex_lock(&(pool->thread_counter));
  253. int busy_thr_num = pool->busy_thr_num; /* 忙着的线程数 */
  254. pthread_mutex_unlock(&(pool->thread_counter));
  255.  
  256. /* 创建新线程 算法: 任务数大于最小线程池个数, 且存活的线程数少于最大线程个数时 如:30>=10 && 40<100*/
  257. if (queue_size >= MIN_WAIT_TASK_NUM && live_thr_num < pool->max_thr_num) {
  258. pthread_mutex_lock(&(pool->lock));
  259. int add = ;
  260.  
  261. /*一次增加 DEFAULT_THREAD 个线程*/
  262. for (i = ; i < pool->max_thr_num && add < DEFAULT_THREAD_VARY
  263. && pool->live_thr_num < pool->max_thr_num; i++) {
  264. if (pool->threads[i] == || !is_thread_alive(pool->threads[i])) {
  265. pthread_create(&(pool->threads[i]), NULL, threadpool_thread, (void *)pool);
  266. add++;
  267. pool->live_thr_num++;
  268. }
  269. }
  270.  
  271. pthread_mutex_unlock(&(pool->lock));
  272. }
  273.  
  274. /* 销毁多余的空闲线程 算法:忙线程X2 小于 存活的线程数 且 存活的线程数 大于 最小线程数时*/
  275. if ((busy_thr_num * ) < live_thr_num && live_thr_num > pool->min_thr_num) {
  276.  
  277. /* 一次销毁DEFAULT_THREAD个线程, 隨機10個即可 */
  278. pthread_mutex_lock(&(pool->lock));
  279. pool->wait_exit_thr_num = DEFAULT_THREAD_VARY; /* 要销毁的线程数 设置为10 */
  280. pthread_mutex_unlock(&(pool->lock));
  281.  
  282. for (i = ; i < DEFAULT_THREAD_VARY; i++) {
  283. /* 通知处在空闲状态的线程, 他们会自行终止*/
  284. pthread_cond_signal(&(pool->queue_not_empty));
  285. }
  286. }
  287. }
  288.  
  289. return NULL;
  290. }
  291.  
  292. //销毁线程:先销毁管理线程,防止添加任务等情况
  293. int threadpool_destroy(threadpool_t *pool)
  294. {
  295. int i;
  296. if (pool == NULL) {
  297. return -;
  298. }
  299. pool->shutdown = true;
  300.  
  301. /*先销毁管理线程*/
  302. pthread_join(pool->adjust_tid, NULL);
  303.  
  304. for (i = ; i < pool->live_thr_num; i++) {
  305. /*通知所有的空闲线程*/
  306. pthread_cond_broadcast(&(pool->queue_not_empty));
  307. }
  308. for (i = ; i < pool->live_thr_num; i++) {
  309. pthread_join(pool->threads[i], NULL);
  310. }
  311. threadpool_free(pool);
  312.  
  313. return ;
  314. }
  315.  
  316. int threadpool_free(threadpool_t *pool)
  317. {
  318. if (pool == NULL) {
  319. return -;
  320. }
  321.  
  322. if (pool->task_queue) {
  323. free(pool->task_queue);
  324. }
  325. if (pool->threads) {
  326. free(pool->threads);
  327. pthread_mutex_lock(&(pool->lock));
  328. pthread_mutex_destroy(&(pool->lock));
  329. pthread_mutex_lock(&(pool->thread_counter));
  330. pthread_mutex_destroy(&(pool->thread_counter));
  331. pthread_cond_destroy(&(pool->queue_not_empty));
  332. pthread_cond_destroy(&(pool->queue_not_full));
  333. }
  334. free(pool);
  335. pool = NULL;
  336.  
  337. return ;
  338. }
  339.  
  340. int threadpool_all_threadnum(threadpool_t *pool)
  341. {
  342. int all_threadnum = -;
  343. pthread_mutex_lock(&(pool->lock));
  344. all_threadnum = pool->live_thr_num;
  345. pthread_mutex_unlock(&(pool->lock));
  346. return all_threadnum;
  347. }
  348.  
  349. int threadpool_busy_threadnum(threadpool_t *pool)
  350. {
  351. int busy_threadnum = -;
  352. pthread_mutex_lock(&(pool->thread_counter));
  353. busy_threadnum = pool->busy_thr_num;
  354. pthread_mutex_unlock(&(pool->thread_counter));
  355. return busy_threadnum;
  356. }
  357.  
  358. int is_thread_alive(pthread_t tid)
  359. {
  360. int kill_rc = pthread_kill(tid, ); //发0号信号,测试线程是否存活
  361. if (kill_rc == ESRCH) {
  362. return false;
  363. }
  364.  
  365. return true;
  366. }
  367.  
  368. /*测试*/
  369.  
  370. #if 1
  371. /* 线程池中的线程,模拟处理业务 */
  372. void *process(void *arg)
  373. {
  374. printf("thread 0x%x working on task %d\n ",(unsigned int)pthread_self(),*(int *)arg);
  375. sleep();
  376. printf("task %d is end\n",*(int *)arg);
  377.  
  378. return NULL;
  379. }
  380. int main(void)
  381. {
  382. /*threadpool_t *threadpool_create(int min_thr_num, int max_thr_num, int queue_max_size);*/
  383.  
  384. threadpool_t *thp = threadpool_create(,,);/*创建线程池,池里最小3个线程,最大100,队列最大100*/
  385. printf("pool inited");
  386.  
  387. //int *num = (int *)malloc(sizeof(int)*20);
  388. int num[], i;
  389. for (i = ; i < ; i++) {
  390. num[i]=i;
  391. printf("add task %d\n",i);
  392. threadpool_add(thp, process, (void*)&num[i]); /* 向线程池中添加任务 */
  393. }
  394. sleep(); /* 等子线程完成任务 */
  395. threadpool_destroy(thp);
  396.  
  397. return ;
  398. }
  399.  
  400. #endif

C,线程池的更多相关文章

  1. 多线程爬坑之路-学习多线程需要来了解哪些东西?(concurrent并发包的数据结构和线程池,Locks锁,Atomic原子类)

    前言:刚学习了一段机器学习,最近需要重构一个java项目,又赶过来看java.大多是线程代码,没办法,那时候总觉得多线程是个很难的部分很少用到,所以一直没下决定去啃,那些年留下的坑,总是得自己跳进去填 ...

  2. C#多线程之线程池篇3

    在上一篇C#多线程之线程池篇2中,我们主要学习了线程池和并行度以及如何实现取消选项的相关知识.在这一篇中,我们主要学习如何使用等待句柄和超时.使用计时器和使用BackgroundWorker组件的相关 ...

  3. C#多线程之线程池篇2

    在上一篇C#多线程之线程池篇1中,我们主要学习了如何在线程池中调用委托以及如何在线程池中执行异步操作,在这篇中,我们将学习线程池和并行度.实现取消选项的相关知识. 三.线程池和并行度 在这一小节中,我 ...

  4. C#多线程之线程池篇1

    在C#多线程之线程池篇中,我们将学习多线程访问共享资源的一些通用的技术,我们将学习到以下知识点: 在线程池中调用委托 在线程池中执行异步操作 线程池和并行度 实现取消选项 使用等待句柄和超时 使用计时 ...

  5. NGINX引入线程池 性能提升9倍

    1. 引言 正如我们所知,NGINX采用了异步.事件驱动的方法来处理连接.这种处理方式无需(像使用传统架构的服务器一样)为每个请求创建额外的专用进程或者线程,而是在一个工作进程中处理多个连接和请求.为 ...

  6. Java线程池解析

    Java的一大优势是能完成多线程任务,对线程的封装和调度非常好,那么它又是如何实现的呢? jdk的包下和线程相关类的类图. 从上面可以看出Java的线程池主的实现类主要有两个类ThreadPoolEx ...

  7. Android线程管理之ExecutorService线程池

    前言: 上篇学习了线程Thread的使用,今天来学习一下线程池ExecutorService. 线程管理相关文章地址: Android线程管理之Thread使用总结 Android线程管理之Execu ...

  8. Android线程管理之ThreadPoolExecutor自定义线程池

    前言: 上篇主要介绍了使用线程池的好处以及ExecutorService接口,然后学习了通过Executors工厂类生成满足不同需求的简单线程池,但是有时候我们需要相对复杂的线程池的时候就需要我们自己 ...

  9. -Android -线程池 批量上传图片 -附php接收代码

    (出处:http://www.cnblogs.com/linguanh/) 目录: 1,前序 2,类特点 3,用法 4,java代码 5,php代码 1,前序 还是源于重构,看着之前为赶时间写着的碎片 ...

  10. C#多线程--线程池(ThreadPool)

    先引入一下线程池的概念: 百度百科:线程池是一种多线程处理形式,处理过程中将任务添加到队列,然后在创建线程后自动启动这些任务.线程池线程都是后台线程.每个线程都使用默认的堆栈大小,以默认的优先级运行, ...

随机推荐

  1. linux命令自动补全

    在linux中命令较长时,不易记忆,使用命令行自动补全,使用方便,配置方法记录如下 需要安装bash-completion 重启后生效 命令:yum install bash-completion,安 ...

  2. Linux:PS查看进程信息,和查看tomcat内存等信息

    版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn.net/fly910905/article/deta ...

  3. 10-MySQlL DBA笔记-基础知识

    第四部分 运维篇 首先来了解一下数据库的定义,数据库是高效的.可靠的.易用的.安全的多用户存储引擎,我们可以通过它访问大量的持久化数据.我们管理和维护数据库,本质上也是要确保如上的特性,尽可能地保证数 ...

  4. C# Extension Methods(C#类方法扩展)

    使用Extension methods 可以在已有的类型(types)中添加方法(Methods),而无需通过增加一种新的类型或修改已有的类型. 比如说,想要给string类型增加一个PrintStr ...

  5. Boost,Eigen,Flann—C++标准库预备役

    Boost,Eigen,Flann—C++标准库预备役 第一预备役:Boost      Boost库是为C++语言标准库提供扩展的一些C++程序库的总称. Boost库由Boost社区组织开发.维护 ...

  6. mbedtls 入门

    mbedtls 入门 https://segmentfault.com/a/1190000012007117 ARM mbedtls使开发人员可以非常轻松地在嵌入式产品中加入加密和SSL/TLS功能. ...

  7. sketch最强切图工具Sketch Measure

    https://www.inpandora.com/sketch-measure.html https://www.jianshu.com/p/c11ae88e6b1d

  8. 通过hadoop上的hive完成WordCount

    1.启动hadoop 打开所有命令:start-all.sh 2.Hdfs上创建文件夹 创建名为PGOne到user/hadoop 3.上传文件至hdfs 创建和修改508.txt文件,里面尽量多写一 ...

  9. Mina TCP服务端客户端 示例

    服务端代码: package com.xd.nms.example; import java.io.IOException; import java.net.InetSocketAddress; im ...

  10. 第三章、Django之路由层

    目录 第三章.Django之路由层 一 路由的作用 二 简单的路由配置 三 分组 四 路由分发 五 反向解析 六 名称空间 七 django2.0版的re_path与path 第三章.Django之路 ...