Linux下c语言线程池的实现

来源:互联网 发布:阿里云备案网站负责人 编辑:程序博客网 时间:2024/05/16 05:20

1.线程池基本原理

  在传统服务器结构中, 常是 有一个总的 监听线程监听有没有新的用户连接服务器, 每当有一个新的用户进入, 服务器就开启一个新的线程用户处理这 个用户的数据包。这个线程只服务于这个用户 , 当 用户与服务器端关闭连接以后,服务器端销毁这个线程。然而频繁地开辟与销毁线程极大地占用了系统的资源。而且在大量用户的情况下,系统为了开辟和销毁线程将浪费大量的时间和资源。线程池提供了一个解决外部大量用户与服务器有限资源的矛盾, 线程池和传统的一个用户对应一个线程的处理方法不同, 它的基本思想就是在程序 开始时就在内存中开辟一些线程, 线程的数目是 固定的,他们独自形成一个类,屏蔽了对外的操作, 而服务器只需要将数据包交给线程池就可以了。当有新的客户请求到达时 , 不是新创建一个线程为其服务 ,而是从“池子”中选择一个空闲的线程为新的客户请求服务 ,服务完毕后 , 线程进入空闲线程池中。如果没有线程空闲 的 话, 就 将 数据 包 暂 时 积 累 , 等 待 线 程 池 内 有 线 程空闲以后再进行处理。通过对多个任务重用已经存在的线程对象 ,降低了对线程对象创建和销毁的开销。当客户请求 时 , 线程对象 已 经 存 在 , 可 以 提 高 请 求 的响应时间 ,从而整体地提高了系统服务的表现。

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

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

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

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

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

下面的不在赘述百度《线程池技术在并发服务器中的应用》写的非常详细!

转自:http://blog.csdn.net/zouxinfox/article/details/3560891

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

   下面是Linux系统下用C语言创建的一个线程池。线程池会维护一个任务链表(每个CThread_worker结构就是一个任务)。
   pool_init()函数预先创建好max_thread_num个线程,每个线程执thread_routine()函数。该函数中

  1. while (pool->cur_queue_size == 0)
  2. {
  3.       pthread_cond_wait (&(pool->queue_ready),&(pool->queue_lock));
  4. }
表示如果任务链表中没有任务,则该线程出于阻塞等待状态。否则从队列中取出任务并执行。
   
   pool_add_worker()函数向线程池的任务链表中加入一个任务,加入后通过调用pthread_cond_signal(&(pool->queue_ready))唤醒一个出于阻塞状态的线程(如果有的话)。
   
    pool_destroy()函数用于销毁线程池,线程池任务链表中的任务不会再被执行,但是正在运行的线程会一直把任务运行完后再退出。

[cpp] viewplain copy
 print?
  1. #include   
  2. #include   
  3. #include   
  4. #include   
  5. #include   
  6. #include   
  7.   
  8.   
  9. typedef struct worker  
  10.  
  11.       
  12.     void *(*process) (void *arg);  
  13.     void *arg;  
  14.     struct worker *next;  
  15.   
  16. CThread_worker;  
  17.   
  18.   
  19.   
  20.   
  21. typedef struct  
  22.  
  23.     pthread_mutex_t queue_lock;  
  24.     pthread_cond_t queue_ready;  
  25.   
  26.       
  27.     CThread_worker *queue_head;  
  28.   
  29.       
  30.     int shutdown;  
  31.     pthread_t *threadid;  
  32.       
  33.     int max_thread_num;  
  34.       
  35.     int cur_queue_size;  
  36.   
  37. CThread_pool;  
  38.   
  39.   
  40.   
  41. int pool_add_worker (void *(*process) (void *arg), void *arg);  
  42. void *thread_routine (void *arg);  
  43.   
  44.   
  45. //share resource  
  46. static CThread_pool *pool NULL;  
  47. void  
  48. pool_init (int max_thread_num)  
  49.  
  50.     pool (CThread_pool *) malloc (sizeof (CThread_pool));  
  51.   
  52.     pthread_mutex_init (&(pool->queue_lock), NULL);  
  53.     pthread_cond_init (&(pool->queue_ready), NULL);  
  54.   
  55.     pool->queue_head NULL;  
  56.   
  57.     pool->max_thread_num max_thread_num;  
  58.     pool->cur_queue_size 0;  
  59.   
  60.     pool->shutdown 0;  
  61.   
  62.     pool->threadid (pthread_t *) malloc (max_thread_num sizeof (pthread_t));  
  63.     int 0;  
  64.     for (i 0; max_thread_num; i++)  
  65.       
  66.         pthread_create (&(pool->threadid[i]), NULL, thread_routine,NULL);  
  67.      
  68.  
  69.   
  70.   
  71.   
  72.   
  73. int  
  74. pool_add_worker (void *(*process) (void *arg), void *arg)  
  75.  
  76.       
  77.     CThread_worker *newworker (CThread_worker *) malloc (sizeof (CThread_worker));  
  78.     newworker->process process;  
  79.     newworker->arg arg;  
  80.     newworker->next NULL;  
  81.   
  82.     pthread_mutex_lock (&(pool->queue_lock));  
  83.       
  84.     CThread_worker *member pool->queue_head;  
  85.     if (member != NULL)  
  86.      
  87.         while (member->next != NULL)  
  88.             member member->next;  
  89.         member->next newworker;  
  90.      
  91.     else  
  92.      
  93.         pool->queue_head newworker;  
  94.      
  95.   
  96.     assert (pool->queue_head != NULL);  
  97.   
  98.     pool->cur_queue_size++;  
  99.     pthread_mutex_unlock (&(pool->queue_lock));  
  100.       
  101.     pthread_cond_signal (&(pool->queue_ready));  
  102.     return 0;  
  103.  
  104.   
  105.   
  106.   
  107.   
  108. int  
  109. pool_destroy ()  
  110.  
  111.     if (pool->shutdown)  
  112.         return -1;  
  113.     pool->shutdown 1;  
  114.   
  115.       
  116.     pthread_cond_broadcast (&(pool->queue_ready));  
  117.   
  118.       
  119.     int i;  
  120.     for (i 0; pool->max_thread_num; i++)  
  121.         pthread_join (pool->threadid[i], NULL);  
  122.     free (pool->threadid);  
  123.   
  124.       
  125.     CThread_worker *head NULL;  
  126.     while (pool->queue_head != NULL)  
  127.      
  128.         head pool->queue_head;  
  129.         pool->queue_head pool->queue_head->next;  
  130.         free (head);  
  131.      
  132.       
  133.     pthread_mutex_destroy(&(pool->queue_lock));  
  134.     pthread_cond_destroy(&(pool->queue_ready));  
  135.       
  136.     free (pool);  
  137.       
  138.     pool=NULL;  
  139.     return 0;  
  140.  
  141.   
  142.   
  143.   
  144. void  
  145. thread_routine (void *arg)  
  146.  
  147.     printf ("starting thread 0x%x\n"pthread_self ());  
  148.     while (1)  
  149.      
  150.         pthread_mutex_lock (&(pool->queue_lock));  
  151.           
  152.         while (pool->cur_queue_size == && !pool->shutdown)  
  153.          
  154.             printf ("thread 0x%x is waiting\n"pthread_self ());  
  155.             pthread_cond_wait (&(pool->queue_ready), &(pool->queue_lock));  
  156.          
  157.   
  158.           
  159.         if (pool->shutdown)  
  160.          
  161.               
  162.             pthread_mutex_unlock (&(pool->queue_lock));  
  163.             printf ("thread 0x%x will exit\n"pthread_self ());  
  164.             pthread_exit (NULL);  
  165.          
  166.   
  167.         printf ("thread 0x%x is starting to work\n"pthread_self ());  
  168.   
  169.           
  170.         assert (pool->cur_queue_size != 0);  
  171.         assert (pool->queue_head != NULL);  
  172.           
  173.           
  174.         pool->cur_queue_size--;  
  175.         CThread_worker *worker pool->queue_head;  
  176.         pool->queue_head worker->next;  
  177.         pthread_mutex_unlock (&(pool->queue_lock));  
  178.   
  179.           
  180.         (*(worker->process)) (worker->arg);  
  181.         free (worker);  
  182.         worker NULL;  
  183.      
  184.       
  185.     pthread_exit (NULL);  
  186.  
  187.   
  188. //    下面是测试代码  
  189.   
  190. void  
  191. myprocess (void *arg)  
  192.  
  193.     printf ("threadid is 0x%x, working on task %d\n"pthread_self (),*(int *) arg);  
  194.     sleep (1);  
  195.     return NULL;  
  196.  
  197.   
  198. int  
  199. main (int argc, char **argv)  
  200.  
  201.     pool_init (3);  
  202.       
  203.       
  204.     int *workingnum (int *) malloc (sizeof (int10);  
  205.     int i;  
  206.     for (i 0; 10; i++)  
  207.      
  208.         workingnum[i] i;  
  209.         pool_add_worker (myprocess, &workingnum[i]);  
  210.      
  211.       
  212.     sleep (5);  
  213.       
  214.     pool_destroy ();  
  215.   
  216.     free (workingnum);  
  217.     return 0;  
  218.  


将上述所有代码放入threadpool.c文件中,
在Linux输入编译命令
$ gcc -o threadpool threadpool.c -lpthread

以下是运行结果
starting thread 0xb7df6b90
thread 0xb7df6b90 is waiting
starting thread 0xb75f5b90
thread 0xb75f5b90 is waiting
starting thread 0xb6df4b90
thread 0xb6df4b90 is waiting
thread 0xb7df6b90 is starting to work
threadid is 0xb7df6b90, working on task 0
thread 0xb75f5b90 is starting to work
threadid is 0xb75f5b90, working on task 1
thread 0xb6df4b90 is starting to work
threadid is 0xb6df4b90, working on task 2
thread 0xb7df6b90 is starting to work
threadid is 0xb7df6b90, working on task 3
thread 0xb75f5b90 is starting to work
threadid is 0xb75f5b90, working on task 4
thread 0xb6df4b90 is starting to work
threadid is 0xb6df4b90, working on task 5
thread 0xb7df6b90 is starting to work
threadid is 0xb7df6b90, working on task 6
thread 0xb75f5b90 is starting to work
threadid is 0xb75f5b90, working on task 7
thread 0xb6df4b90 is starting to work
threadid is 0xb6df4b90, working on task 8
thread 0xb7df6b90 is starting to work
threadid is 0xb7df6b90, working on task 9
thread 0xb75f5b90 is waiting
thread 0xb6df4b90 is waiting
thread 0xb7df6b90 is waiting
thread 0xb75f5b90 will exit
thread 0xb6df4b90 will exit
thread 0xb7df6b90 will exit
0 0