http://blog.csdn.net/tennysonsky/article/details/46490099#

线程池基本原理

在传统服务器结构中,常是有一个总的监听线程监听有没有新的用户连接服务器,每当有一个新的用户进入,服务器就开启一个新的线程用户处理这 个用户的数据包。这个线程只服务于这个用户,当用户与服务器端关闭连接以后,服务器端销毁这个线程。(关于并发服务器更多详情,请看《并发服务器》)。

然而频繁地开辟与销毁线程极大地占用了系统的资源,而且在大量用户的情况下,系统为了开辟和销毁线程将浪费大量的时间和资源。线程池提供了一个解决外部大量用户与服务器有限资源的矛盾。

线程池和传统的一个用户对应一个线程的处理方法不同,它的基本思想就是在程序开始时就在内存中开辟一些线程,线程的数目是固定的,他们独自形成一个类,屏蔽了对外的操作,而服务器只需要将数据包交给线程池就可以了。当有新的客户请求到达时,不是新创建一个线程为其服务,而是从“池子”中选择一个空闲的线程为新的客户请求服务,服务完毕后,线程进入空闲线程池中。如果没有线程空闲的话,就将数据包暂时积累, 等待线程池内有线程空闲以后再进行处理。通过对多个任务重用已经存在的线程对象,降低了对线程对象创建和销毁的开销。当客户请求 时,线程对象已经存在,可以提高请求的响应时间,从而整体地提高了系统服务的表现。

线程池应用实例

一般来说实现一个线程池主要包括以下几个组成部分:

1)线程管理器:用于创建并管理线程池。

2)工作线程:线程池中实际执行任务的线程。在初始化线程时会预先创建好固定数目的线程在池中,这些初始化的线程一般处于空闲状态,一般不占用 CPU,占用较小的内存空间。

3)任务接口:每个任务必须实现的接口,当线程池的任务队列中有可执行任务时,被空闲的工作线程调去执行(线程的闲与忙是通过互斥量实现的),把任务抽象出来形成接口,可以做到线程池与具体的任务无关。

4)任务队列:用来存放没有处理的任务,提供一种缓冲机制,实现这种结构有好几种方法,常用的是队列,主要运用先进先出原理,另外一种是链表之类的数据结构,可以动态的为它分配内存空间,应用中比较灵活,此教程就是用到的链表。

什么时候需要创建线程池呢?简单的说,如果一个应用需要频繁的创建和销毁线程,而任务执行的时间又非常短,这样线程创建和销毁的带来的开销就不容忽视,这时也是线程池该出场的机会了。如果线程创建和销毁时间相比任务执行时间可以忽略不计,则没有必要使用线程池了。

线程池实现示例代码如下:

thread_pool.h 的示例代码:

[cpp] view plaincopy
  1. #ifndef __THREAD_POOL_H__
  2. #define __THREAD_POOL_H__
  3. #include <pthread.h>
  4. /*********************************************************************
  5. * 任务回调函数,也可根据需要自行修改
  6. *********************************************************************/
  7. typedef void *(*pool_task_f)(void *arg);
  8. /*********************************************************************
  9. * 任务句柄
  10. *********************************************************************/
  11. typedef struct _task{
  12. pool_task_f process;/*回调函数,任务运行时会调用此函数,注意也可声明成其它形式*/
  13. void *arg;     /*回调函数的参数*/
  14. struct _task *next;
  15. }pool_task;
  16. /*********************************************************************
  17. * 线程池句柄
  18. *********************************************************************/
  19. typedef struct
  20. {
  21. pthread_t *threadid;        /* 线程号 */
  22. int threads_limit;          /* 线程池中允许的活动线程数目 */
  23. int destroy_flag;           /* 是否销毁线程池 , 0销毁,1不销毁*/
  24. pool_task *queue_head;      /* 链表结构,线程池中所有等待任务 */
  25. int task_in_queue;          /* 当前等待队列的任务数目 */
  26. pthread_mutex_t queue_lock; /* 锁 */
  27. pthread_cond_t queue_ready; /* 条件变量 */
  28. }pool_t;
  29. /*********************************************************************
  30. *功能:        初始化线程池结构体并创建线程
  31. *参数:
  32. pool:线程池句柄
  33. threads_limit:线程池中线程的数量
  34. *返回值:   无
  35. *********************************************************************/
  36. void pool_init(pool_t *pool, int threads_limit);
  37. /*********************************************************************
  38. *功能:        销毁线程池,等待队列中的任务不会再被执行,
  39. 但是正在运行的线程会一直,把任务运行完后再退出
  40. *参数:        线程池句柄
  41. *返回值:   成功:0,失败非0
  42. *********************************************************************/
  43. int pool_uninit(pool_t *pool);
  44. /*********************************************************************
  45. *功能:        向线程池中添加一个任务
  46. *参数:
  47. pool:线程池句柄
  48. process:任务处理函数
  49. arg:任务参数
  50. *返回值:   0
  51. *********************************************************************/
  52. int pool_add_task(pool_t *pool, pool_task_f process, void *arg);
  53. #endif

thread_pool.c 的示例代码:

[cpp] view plaincopy
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <pthread.h>
  4. #include <assert.h>
  5. #include "thread_pool.h"
  6. static void *pool_thread_server(void *arg);
  7. /*********************************************************************
  8. *功能:        初始化线程池结构体并创建线程
  9. *参数:
  10. pool:线程池句柄
  11. threads_limit:线程池中线程的数量
  12. *返回值:   无
  13. *********************************************************************/
  14. void pool_init(pool_t *pool, int threads_limit)
  15. {
  16. pool->threads_limit = threads_limit;
  17. pool->queue_head = NULL;
  18. pool->task_in_queue = 0;
  19. pool->destroy_flag = 0;
  20. /*创建存放线程ID的空间*/
  21. pool->threadid = (pthread_t *)calloc(threads_limit, sizeof(pthread_t));
  22. int i = 0;
  23. /*初始化互斥锁和条件变量*/
  24. pthread_mutex_init(&(pool->queue_lock), NULL);
  25. pthread_cond_init(&(pool->queue_ready), NULL);
  26. /*循环创建threads_limit个线程*/
  27. for (i = 0; i < threads_limit; i++){
  28. pthread_create(&(pool->threadid[i]), NULL, pool_thread_server, pool);
  29. }
  30. return;
  31. }
  32. /*********************************************************************
  33. *功能:        销毁线程池,等待队列中的任务不会再被执行,
  34. 但是正在运行的线程会一直,把任务运行完后再退出
  35. *参数:        线程池句柄
  36. *返回值:   成功:0,失败非0
  37. *********************************************************************/
  38. int pool_uninit(pool_t *pool)
  39. {
  40. pool_task *head = NULL;
  41. int i;
  42. pthread_mutex_lock(&(pool->queue_lock));
  43. if(pool->destroy_flag)/* 防止两次调用 */
  44. return -1;
  45. pool->destroy_flag = 1;
  46. pthread_mutex_unlock(&(pool->queue_lock));
  47. /* 唤醒所有等待线程,线程池要销毁了 */
  48. pthread_cond_broadcast(&(pool->queue_ready));
  49. /* 阻塞等待线程退出,否则就成僵尸了 */
  50. for (i = 0; i < pool->threads_limit; i++)
  51. pthread_join(pool->threadid[i], NULL);
  52. free(pool->threadid);
  53. /* 销毁等待队列 */
  54. pthread_mutex_lock(&(pool->queue_lock));
  55. while(pool->queue_head != NULL){
  56. head = pool->queue_head;
  57. pool->queue_head = pool->queue_head->next;
  58. free(head);
  59. }
  60. pthread_mutex_unlock(&(pool->queue_lock));
  61. /*条件变量和互斥量也别忘了销毁*/
  62. pthread_mutex_destroy(&(pool->queue_lock));
  63. pthread_cond_destroy(&(pool->queue_ready));
  64. return 0;
  65. }
  66. /*********************************************************************
  67. *功能:        向任务队列中添加一个任务
  68. *参数:
  69. pool:线程池句柄
  70. process:任务处理函数
  71. arg:任务参数
  72. *返回值:   无
  73. *********************************************************************/
  74. static void enqueue_task(pool_t *pool, pool_task_f process, void *arg)
  75. {
  76. pool_task *task = NULL;
  77. pool_task *member = NULL;
  78. pthread_mutex_lock(&(pool->queue_lock));
  79. if(pool->task_in_queue >= pool->threads_limit){
  80. printf("task_in_queue > threads_limit!\n");
  81. pthread_mutex_unlock (&(pool->queue_lock));
  82. return;
  83. }
  84. task = (pool_task *)calloc(1, sizeof(pool_task));
  85. assert(task != NULL);
  86. task->process = process;
  87. task->arg = arg;
  88. task->next = NULL;
  89. pool->task_in_queue++;
  90. member = pool->queue_head;
  91. if(member != NULL){
  92. while(member->next != NULL)  /* 将任务加入到任务链连的最后位置. */
  93. member = member->next;
  94. member->next = task;
  95. }else{
  96. pool->queue_head = task; /* 如果是第一个任务的话,就指向头 */
  97. }
  98. printf("\ttasks %d\n", pool->task_in_queue);
  99. /* 等待队列中有任务了,唤醒一个等待线程 */
  100. pthread_cond_signal (&(pool->queue_ready));
  101. pthread_mutex_unlock (&(pool->queue_lock));
  102. }
  103. /*********************************************************************
  104. *功能:        从任务队列中取出一个任务
  105. *参数:        线程池句柄
  106. *返回值:   任务句柄
  107. *********************************************************************/
  108. static pool_task *dequeue_task(pool_t *pool)
  109. {
  110. pool_task *task = NULL;
  111. pthread_mutex_lock(&(pool->queue_lock));
  112. /* 判断线程池是否要销毁了 */
  113. if(pool->destroy_flag){
  114. pthread_mutex_unlock(&(pool->queue_lock));
  115. printf("thread 0x%lx will be destroyed\n", pthread_self());
  116. pthread_exit(NULL);
  117. }
  118. /* 如果等待队列为0并且不销毁线程池,则处于阻塞状态 */
  119. if(pool->task_in_queue == 0){
  120. while((pool->task_in_queue == 0) && (!pool->destroy_flag)){
  121. printf("thread 0x%lx is waitting\n", pthread_self());
  122. /* 注意:pthread_cond_wait是一个原子操作,等待前会解锁,唤醒后会加锁 */
  123. pthread_cond_wait(&(pool->queue_ready), &(pool->queue_lock));
  124. }
  125. }else{
  126. /* 等待队列长度减去1,并取出队列中的第一个元素 */
  127. pool->task_in_queue--;
  128. task = pool->queue_head;
  129. pool->queue_head = task->next;
  130. printf("thread 0x%lx received a task\n", pthread_self());
  131. }
  132. pthread_mutex_unlock(&(pool->queue_lock));
  133. return task;
  134. }
  135. /*********************************************************************
  136. *功能:        向线程池中添加一个任务
  137. *参数:
  138. pool:线程池句柄
  139. process:任务处理函数
  140. arg:任务参数
  141. *返回值:   0
  142. *********************************************************************/
  143. int pool_add_task(pool_t *pool, pool_task_f process, void *arg)
  144. {
  145. enqueue_task(pool, process, arg);
  146. return 0;
  147. }
  148. /*********************************************************************
  149. *功能:        线程池服务程序
  150. *参数:        略
  151. *返回值:   略
  152. *********************************************************************/
  153. static void *pool_thread_server(void *arg)
  154. {
  155. pool_t *pool = NULL;
  156. pool = (pool_t *)arg;
  157. while(1){
  158. pool_task *task = NULL;
  159. task = dequeue_task(pool);
  160. /*调用回调函数,执行任务*/
  161. if(task != NULL){
  162. printf ("thread 0x%lx is busy\n", pthread_self());
  163. task->process(task->arg);
  164. free(task);
  165. task = NULL;
  166. }
  167. }
  168. /*这一句应该是不可达的*/
  169. pthread_exit(NULL);
  170. return NULL;
  171. }

下面是测试代码:

[cpp] view plaincopy
  1. #include <stdio.h>
  2. #include <unistd.h>
  3. #include "thread_pool.h"
  4. void *task_test(void *arg)
  5. {
  6. printf("\t\tworking on task %d\n", (int)arg);
  7. sleep(1);           /*休息一秒,延长任务的执行时间*/
  8. return NULL;
  9. }
  10. void thread_pool_demo(void)
  11. {
  12. pool_t pool;
  13. int i = 0;
  14. pool_init(&pool, 2);//初始化一个线程池,其中创建2个线程
  15. sleep(1);
  16. for(i = 0; i < 5; i++){
  17. sleep(1);
  18. pool_add_task(&pool, task_test, (void *)i);//添加一个任务
  19. }
  20. sleep(4);
  21. pool_uninit(&pool);//删除线程池
  22. }
  23. int main (int argc, char *argv[])
  24. {
  25. thread_pool_demo();
  26. return 0;
  27. }

运行结果如下:

本教程示例代码下载请点此处。

参考资料:http://blog.csdn.net/hubi0952

Linux系统编程——线程池相关推荐

  1. Linux系统编程——线程私有数据

    在多线程程序中.常常要用全局变量来实现多个函数间的数据共享.因为数据空间是共享的,因此全局变量也为全部线程共同拥有. 測试代码例如以下: #include <stdio.h> #inclu ...

  2. Linux系统编程——线程(1)

    目录 线程概要 Linux内核线程实现原理 线程的共享/不共享资源 线程优缺点 线程控制原语 pthread_self pthread_create pthread_exit pthread_join ...

  3. Linux系统编程——线程

    一.线程概念 基础 线程又称LWP:light weight process 轻量级的进程,(在linux环境下)本质仍是进程.进程:独立地址空间,拥有PCB 线程:有独立的PCB,但没有独立的地址空 ...

  4. 入门Linux系统编程--网络编程

    文章目录 一.网络编程 1.socket服务端代码实现(无连接客户端) 6.socket服务端代码实现(连接客户端) 7.socket客户端代码实现 8.实现双方聊天 9.多方消息收发 二.往期文章 ...

  5. Linux系统编程之进程与线程控制原语对比

    Linux系统编程之进程与线程控制原语对比 进程 线程 fork pthread_create exit pthread_exit wait pthread_join kill pthread_can ...

  6. linux线程并不真正并行,Linux系统编程学习札记(十二)线程1

    Linux系统编程学习笔记(十二)线程1 线程1: 线程和进程类似,但是线程之间能够共享更多的信息.一个进程中的所有线程可以共享进程文件描述符和内存. 有了多线程控制,我们可以把我们的程序设计成为在一 ...

  7. Linux系统编程(九)线程同步

    Linux系统编程(九)线程同步 一.什么是线程同步? 二.互斥量 三.条件变量 pthread_cond_wait函数 pthread_cond_signal函数 生产者和消费者模型 一.什么是线程 ...

  8. Linux系统编程(八)线程

    Linux系统编程(八)线程 一.什么是线程? 二.Linux内核线程实现原理 线程共享资源 线程非共享资源 线程优缺点 线程控制原语 一.什么是线程? LWP:light weight proces ...

  9. 【Linux | 系统编程】Linux系统编程(文件、进程线程、进程间通信)

    文章目录 Linux系统编程 文件IO open/close函数 read/write函数 文件描述符 阻塞.非阻塞 fcntl函数 lseek函数 传入传出参数 文件系统 文件存储 文件操作 sta ...

最新文章

  1. Node中的Http模块和Url模块的使用
  2. 文字处理的标签及属性
  3. read函数头文件 window_of_property_read_string 剖析
  4. 洛谷P2879 [USACO07JAN]区间统计Tallest Cow
  5. 服务器自动删路由,云服务器Windows下添加、删除和修改静态路由
  6. Python基础2-Python中文乱码(转)
  7. 网易云 NeteaseCloudMusicApi 码云下载
  8. Matlab鲁棒控制工具箱(Robust Control Toolbox)
  9. FixFox 打包xpi扩展
  10. java中的match函数_js 正则表达式中的match函数
  11. vue 在线预览 word ,Excel,pdf,图片 数据流 内网文件流 亲测有效(word 目前支持docx文件以及doc文件(doc需要后端处理))
  12. 免费P2P穿透通信(4) RDT可靠通信模块测试使用
  13. 梦幻西游网页版服务器,服务器荣辱战,《梦幻西游网页版》梦幻攻防战“挖矿人”经验来啦...
  14. 数据可视化笔记8 层次数据可视化
  15. 如何将revit的内建模型导出使用?项目族管理功能介绍
  16. Daily Scrum Meeting 11.13
  17. 【渝粤教育】广东开放大学 应用创意写作 形成性考核 (54)
  18. JavaScript基础学习——第五天(原型、垃圾回收、数组简介)
  19. c语言中f5的作用,3G的AKA协议中F1至F5的UE端的实现(附代码C语言)
  20. 猪八戒威客网对我的报道

热门文章

  1. jenkins jar包上传maven仓库
  2. Eclipse安装TestNG插件
  3. 解决ueditor jquery javascript 取值问题
  4. 远程工作时的协作工具
  5. 内核编译配置选项含义
  6. 在查询的结果中添加自增列 两种方法
  7. android unbound prefix
  8. java使用impala存放多条sql_Impala基于内存的SQL引擎的详细介绍
  9. 福州java培训哪里好_南通java培训哪家好
  10. python 比较运算符放在列表中_在Python3中将运算符放在列表中