线程池

线程池:创建一定数量(建议:CPU个数 * 2)的线程去执行很多个任务,它通常面向的是一个队列。

一个典型的用法是,有许多个任务远超过线程池数量,将任务放进队列,多个线程则不断的从队列中取出任务执行,直到所有任务都完成,线程可以终止或者睡眠等待新任务的到来。

线程池的伸缩性对性能有较大的影响。

  • 创建太多线程,将会浪费一定的资源,有些线程未被充分使用。
  • 銷毀太多執行緒,將導致之後浪費時間再次創建它們。
  • 创建线程太慢,将会导致長時間的等待,性能變差。
  • 銷毀執行緒太慢,导致其它執行緒资源饥饿。


这里有个线程池的实现:
[cpp]  view plain copy
  1. // spthread.h  
  2.   
  3. #ifndef __spthread_hpp__  
  4. #define __spthread_hpp__  
  5.   
  6. #ifndef WIN32  
  7.   
  8. /// pthread  
  9.   
  10. #include <pthread.h>  
  11. #include <unistd.h>  
  12.   
  13. typedef void * sp_thread_result_t;  
  14. typedef pthread_mutex_t sp_thread_mutex_t;  
  15. typedef pthread_cond_t  sp_thread_cond_t;  
  16. typedef pthread_t       sp_thread_t;  
  17. typedef pthread_attr_t  sp_thread_attr_t;  
  18.   
  19. #define sp_thread_mutex_init(m,a)   pthread_mutex_init(m,a)  
  20. #define sp_thread_mutex_destroy(m)  pthread_mutex_destroy(m)  
  21. #define sp_thread_mutex_lock(m)     pthread_mutex_lock(m)  
  22. #define sp_thread_mutex_unlock(m)   pthread_mutex_unlock(m)  
  23.   
  24. #define sp_thread_cond_init(c,a)    pthread_cond_init(c,a)  
  25. #define sp_thread_cond_destroy(c)   pthread_cond_destroy(c)  
  26. #define sp_thread_cond_wait(c,m)    pthread_cond_wait(c,m)  
  27. #define sp_thread_cond_signal(c)    pthread_cond_signal(c)  
  28.   
  29. #define sp_thread_attr_init(a)        pthread_attr_init(a)  
  30. #define sp_thread_attr_setdetachstate pthread_attr_setdetachstate  
  31. #define SP_THREAD_CREATE_DETACHED     PTHREAD_CREATE_DETACHED  
  32.   
  33. #define sp_thread_self    pthread_self  
  34. #define sp_thread_create  pthread_create  
  35.   
  36. #define SP_THREAD_CALL  
  37. typedef sp_thread_result_t ( * sp_thread_func_t )( void * args );  
  38.   
  39. #define sp_sleep(x) sleep(x)  
  40.   
  41. #else ///  
  42.   
  43. // win32 thread  
  44.   
  45. #include <winsock2.h>  
  46. #include <process.h>  
  47.   
  48. typedef unsigned sp_thread_t;  
  49.   
  50. typedef unsigned sp_thread_result_t;  
  51. #define SP_THREAD_CALL __stdcall  
  52. typedef sp_thread_result_t ( __stdcall * sp_thread_func_t )( void * args );  
  53.   
  54. typedef HANDLE  sp_thread_mutex_t;  
  55. typedef HANDLE  sp_thread_cond_t;  
  56. typedef DWORD   sp_thread_attr_t;  
  57.   
  58. #define SP_THREAD_CREATE_DETACHED 1  
  59. #define sp_sleep(x) Sleep(1000*x)  
  60.   
  61. int sp_thread_mutex_init( sp_thread_mutex_t * mutex, void * attr )  
  62. {  
  63.     *mutex = CreateMutex( NULL, FALSE, NULL );  
  64.     return NULL == * mutex ? GetLastError() : 0;  
  65. }  
  66.   
  67. int sp_thread_mutex_destroy( sp_thread_mutex_t * mutex )  
  68. {  
  69.     int ret = CloseHandle( *mutex );  
  70.   
  71.     return 0 == ret ? GetLastError() : 0;  
  72. }  
  73.   
  74. int sp_thread_mutex_lock( sp_thread_mutex_t * mutex )  
  75. {  
  76.     int ret = WaitForSingleObject( *mutex, INFINITE );  
  77.     return WAIT_OBJECT_0 == ret ? 0 : GetLastError();  
  78. }  
  79.   
  80. int sp_thread_mutex_unlock( sp_thread_mutex_t * mutex )  
  81. {  
  82.     int ret = ReleaseMutex( *mutex );  
  83.     return 0 != ret ? 0 : GetLastError();  
  84. }  
  85.   
  86. int sp_thread_cond_init( sp_thread_cond_t * cond, void * attr )  
  87. {  
  88.     *cond = CreateEvent( NULL, FALSE, FALSE, NULL );  
  89.     return NULL == *cond ? GetLastError() : 0;  
  90. }  
  91.   
  92. int sp_thread_cond_destroy( sp_thread_cond_t * cond )  
  93. {  
  94.     int ret = CloseHandle( *cond );  
  95.     return 0 == ret ? GetLastError() : 0;  
  96. }  
  97.   
  98. /* 
  99. Caller MUST be holding the mutex lock; the 
  100. lock is released and the caller is blocked waiting 
  101. on 'cond'. When 'cond' is signaled, the mutex 
  102. is re-acquired before returning to the caller. 
  103. */  
  104. int sp_thread_cond_wait( sp_thread_cond_t * cond, sp_thread_mutex_t * mutex )  
  105. {  
  106.     int ret = 0;  
  107.   
  108.     sp_thread_mutex_unlock( mutex );  
  109.   
  110.     ret = WaitForSingleObject( *cond, INFINITE );  
  111.   
  112.     sp_thread_mutex_lock( mutex );  
  113.   
  114.     return WAIT_OBJECT_0 == ret ? 0 : GetLastError();  
  115. }  
  116.   
  117. int sp_thread_cond_signal( sp_thread_cond_t * cond )  
  118. {  
  119.     int ret = SetEvent( *cond );  
  120.     return 0 == ret ? GetLastError() : 0;  
  121. }  
  122.   
  123. sp_thread_t sp_thread_self()  
  124. {  
  125.     return GetCurrentThreadId();  
  126. }  
  127.   
  128. int sp_thread_attr_init( sp_thread_attr_t * attr )  
  129. {  
  130.     *attr = 0;  
  131.     return 0;  
  132. }  
  133.   
  134. int sp_thread_attr_setdetachstate( sp_thread_attr_t * attr, int detachstate )  
  135. {  
  136.     *attr |= detachstate;  
  137.     return 0;  
  138. }  
  139.   
  140. int sp_thread_create( sp_thread_t * thread, sp_thread_attr_t * attr,  
  141.         sp_thread_func_t myfunc, void * args )  
  142. {  
  143.     // _beginthreadex returns 0 on an error  
  144.     HANDLE h = (HANDLE)_beginthreadex( NULL, 0, myfunc, args, 0, thread );  
  145.     return h > 0 ? 0 : GetLastError();  
  146. }  
  147.   
  148. #endif  
  149.   
  150. #endif  


[cpp]  view plain copy
  1. /** 
  2.  * threadpool.h 
  3.  * 
  4.  * This file declares the functionality associated with 
  5.  * your implementation of a threadpool. 
  6.  */  
  7.   
  8. #ifndef __threadpool_h__  
  9. #define __threadpool_h__  
  10.   
  11. #ifdef __cplusplus  
  12. extern "C" {  
  13. #endif  
  14.   
  15. // maximum number of threads allowed in a pool  
  16. #define MAXT_IN_POOL 200  
  17.   
  18. // You must hide the internal details of the threadpool  
  19. // structure from callers, thus declare threadpool of type "void".  
  20. // In threadpool.c, you will use type conversion to coerce  
  21. // variables of type "threadpool" back and forth to a  
  22. // richer, internal type.  (See threadpool.c for details.)  
  23.   
  24. typedef void *threadpool;  
  25.   
  26. // "dispatch_fn" declares a typed function pointer.  A  
  27. // variable of type "dispatch_fn" points to a function  
  28. // with the following signature:  
  29. //  
  30. //     void dispatch_function(void *arg);  
  31.   
  32. typedef void (*dispatch_fn)(void *);  
  33.   
  34. /** 
  35.  * create_threadpool creates a fixed-sized thread 
  36.  * pool.  If the function succeeds, it returns a (non-NULL) 
  37.  * "threadpool", else it returns NULL. 
  38.  */  
  39. threadpool create_threadpool(int num_threads_in_pool);  
  40.   
  41.   
  42. /** 
  43.  * dispatch sends a thread off to do some work.  If 
  44.  * all threads in the pool are busy, dispatch will 
  45.  * block until a thread becomes free and is dispatched. 
  46.  * 
  47.  * Once a thread is dispatched, this function returns 
  48.  * immediately. 
  49.  * 
  50.  * The dispatched thread calls into the function 
  51.  * "dispatch_to_here" with argument "arg". 
  52.  */  
  53. int dispatch_threadpool(threadpool from_me, dispatch_fn dispatch_to_here,  
  54.           void *arg);  
  55.   
  56. /** 
  57.  * destroy_threadpool kills the threadpool, causing 
  58.  * all threads in it to commit suicide, and then 
  59.  * frees all the memory associated with the threadpool. 
  60.  */  
  61. void destroy_threadpool(threadpool destroyme);  
  62.   
  63. #ifdef __cplusplus  
  64. }  
  65. #endif  
  66.   
  67. #endif  

[cpp]  view plain copy
  1. /** 
  2.  * threadpool.c 
  3.  * 
  4.  * This file will contain your implementation of a threadpool. 
  5.  */  
  6.   
  7. #include <stdio.h>  
  8. #include <stdlib.h>  
  9. #include <string.h>  
  10.   
  11. #include "ThreadPool.h"  
  12. #include "spthread.h"  
  13.   
  14. typedef struct _thread_st {  
  15.     sp_thread_t id;  
  16.     sp_thread_mutex_t mutex;  
  17.     sp_thread_cond_t cond;  
  18.     dispatch_fn fn;  
  19.     void *arg;  
  20.     threadpool parent;  
  21. } _thread;  
  22.   
  23. // _threadpool is the internal threadpool structure that is  
  24. // cast to type "threadpool" before it given out to callers  
  25. typedef struct _threadpool_st {  
  26.     // you should fill in this structure with whatever you need  
  27.     sp_thread_mutex_t tp_mutex;  
  28.     sp_thread_cond_t tp_idle;  
  29.     sp_thread_cond_t tp_full;  
  30.     sp_thread_cond_t tp_empty;  
  31.     _thread ** tp_list;  
  32.     int tp_index;  
  33.     int tp_max_index;  
  34.     int tp_stop;  
  35.   
  36.     int tp_total;  
  37. } _threadpool;  
  38.   
  39. threadpool create_threadpool(int num_threads_in_pool)  
  40. {  
  41.     _threadpool *pool;  
  42.   
  43.     // sanity check the argument  
  44.     if ((num_threads_in_pool <= 0) || (num_threads_in_pool > MAXT_IN_POOL))  
  45.         return NULL;  
  46.   
  47.     pool = (_threadpool *) malloc(sizeof(_threadpool));  
  48.     if (pool == NULL) {  
  49.         fprintf(stderr, "Out of memory creating a new threadpool!\n");  
  50.         return NULL;  
  51.     }  
  52.   
  53.     // add your code here to initialize the newly created threadpool  
  54.     sp_thread_mutex_init( &pool->tp_mutex, NULL );  
  55.     sp_thread_cond_init( &pool->tp_idle, NULL );  
  56.     sp_thread_cond_init( &pool->tp_full, NULL );  
  57.     sp_thread_cond_init( &pool->tp_empty, NULL );  
  58.     pool->tp_max_index = num_threads_in_pool;  
  59.     pool->tp_index = 0;  
  60.     pool->tp_stop = 0;  
  61.     pool->tp_total = 0;  
  62.     pool->tp_list = ( _thread ** )malloc( sizeofvoid * ) * MAXT_IN_POOL );  
  63.     memset( pool->tp_list, 0, sizeofvoid * ) * MAXT_IN_POOL );  
  64.   
  65.     return (threadpool) pool;  
  66. }  
  67.   
  68. int save_thread( _threadpool * pool, _thread * thread )  
  69. {  
  70.     int ret = -1;  
  71.   
  72.     sp_thread_mutex_lock( &pool->tp_mutex );  
  73.   
  74.     if( pool->tp_index < pool->tp_max_index ) {  
  75.         pool->tp_list[ pool->tp_index ] = thread;  
  76.         pool->tp_index++;  
  77.         ret = 0;  
  78.   
  79.         sp_thread_cond_signal( &pool->tp_idle );  
  80.   
  81.         if( pool->tp_index >= pool->tp_total ) {  
  82.             sp_thread_cond_signal( &pool->tp_full );  
  83.         }  
  84.     }  
  85.   
  86.     sp_thread_mutex_unlock( &pool->tp_mutex );  
  87.   
  88.     return ret;  
  89. }  
  90.   
  91. sp_thread_result_t SP_THREAD_CALL wrapper_fn( void * arg )  
  92. {  
  93.     _thread * thread = (_thread*)arg;  
  94.     _threadpool * pool = (_threadpool*)thread->parent;  
  95.   
  96.     for( ; 0 == ((_threadpool*)thread->parent)->tp_stop; ) {  
  97.         thread->fn( thread->arg );  
  98.   
  99.         if( 0 != ((_threadpool*)thread->parent)->tp_stop ) break;  
  100.   
  101.         sp_thread_mutex_lock( &thread->mutex );  
  102.         if( 0 == save_thread(pool, thread ) ) {  
  103.             sp_thread_cond_wait( &thread->cond, &thread->mutex );  
  104.             sp_thread_mutex_unlock( &thread->mutex );  
  105.         } else {  
  106.             sp_thread_mutex_unlock( &thread->mutex );  
  107.             sp_thread_cond_destroy( &thread->cond );  
  108.             sp_thread_mutex_destroy( &thread->mutex );  
  109.   
  110.             free( thread );  
  111.             break;  
  112.         }  
  113.     }  
  114.   
  115.     sp_thread_mutex_lock( &pool->tp_mutex );  
  116.     pool->tp_total--;  
  117.     if( pool->tp_total <= 0 ) sp_thread_cond_signal( &pool->tp_empty );  
  118.     sp_thread_mutex_unlock( &pool->tp_mutex );  
  119.   
  120.     return 0;  
  121. }  
  122.   
  123. int dispatch_threadpool(threadpool from_me, dispatch_fn dispatch_to_here, void *arg)  
  124. {  
  125.     int ret = 0;  
  126.   
  127.     _threadpool *pool = (_threadpool *) from_me;  
  128.     sp_thread_attr_t attr;  
  129.     _thread * thread = NULL;  
  130.   
  131.     // add your code here to dispatch a thread  
  132.     sp_thread_mutex_lock( &pool->tp_mutex );  
  133.   
  134.     while( pool->tp_index <= 0 && pool->tp_total >= pool->tp_max_index ) {  
  135.         sp_thread_cond_wait( &pool->tp_idle, &pool->tp_mutex );  
  136.     }  
  137.   
  138.     if( pool->tp_index <= 0 ) {  
  139.         _thread * thread = ( _thread * )malloc( sizeof( _thread ) );  
  140.         memset( &( thread->id ), 0, sizeofthread->id ) );  
  141.         sp_thread_mutex_init( &thread->mutex, NULL );  
  142.         sp_thread_cond_init( &thread->cond, NULL );  
  143.         thread->fn = dispatch_to_here;  
  144.         thread->arg = arg;  
  145.         thread->parent = pool;  
  146.   
  147.         sp_thread_attr_init( &attr );  
  148.         sp_thread_attr_setdetachstate( &attr, SP_THREAD_CREATE_DETACHED );  
  149.   
  150.         if( 0 == sp_thread_create( &thread->id, &attr, wrapper_fn, thread ) ) {  
  151.             pool->tp_total++;  
  152.             printf( "create thread#%ld\n"thread->id );  
  153.         } else {  
  154.             ret = -1;  
  155.             printf( "cannot create thread\n" );  
  156.             sp_thread_mutex_destroy( &thread->mutex );  
  157.             sp_thread_cond_destroy( &thread->cond );  
  158.             free( thread );  
  159.         }  
  160.     } else {  
  161.         pool->tp_index--;  
  162.         thread = pool->tp_list[ pool->tp_index ];  
  163.         pool->tp_list[ pool->tp_index ] = NULL;  
  164.   
  165.         thread->fn = dispatch_to_here;  
  166.         thread->arg = arg;  
  167.         thread->parent = pool;  
  168.   
  169.         sp_thread_mutex_lock( &thread->mutex );  
  170.         sp_thread_cond_signal( &thread->cond ) ;  
  171.         sp_thread_mutex_unlock ( &thread->mutex );  
  172.     }  
  173.   
  174.     sp_thread_mutex_unlock( &pool->tp_mutex );  
  175.   
  176.     return ret;  
  177. }  
  178.   
  179. void destroy_threadpool(threadpool destroyme)  
  180. {  
  181.     _threadpool *pool = (_threadpool *) destroyme;  
  182.   
  183.     // add your code here to kill a threadpool  
  184.     int i = 0;  
  185.   
  186.     sp_thread_mutex_lock( &pool->tp_mutex );  
  187.   
  188.     if( pool->tp_index < pool->tp_total ) {  
  189.         printf( "waiting for %d thread(s) to finish\n", pool->tp_total - pool->tp_index );  
  190.         sp_thread_cond_wait( &pool->tp_full, &pool->tp_mutex );  
  191.     }  
  192.   
  193.     pool->tp_stop = 1;  
  194.   
  195.     for( i = 0; i < pool->tp_index; i++ ) {  
  196.         _thread * thread = pool->tp_list[ i ];  
  197.   
  198.         sp_thread_mutex_lock( &thread->mutex );  
  199.         sp_thread_cond_signal( &thread->cond ) ;  
  200.         sp_thread_mutex_unlock ( &thread->mutex );  
  201.     }  
  202.   
  203.     if( pool->tp_total > 0 ) {  
  204.         printf( "waiting for %d thread(s) to exit\n", pool->tp_total );  
  205.         sp_thread_cond_wait( &pool->tp_empty, &pool->tp_mutex );  
  206.     }  
  207.   
  208.     for( i = 0; i < pool->tp_index; i++ ) {  
  209.         free( pool->tp_list[ i ] );  
  210.         pool->tp_list[ i ] = NULL;  
  211.     }  
  212.   
  213.     sp_thread_mutex_unlock( &pool->tp_mutex );  
  214.   
  215.     pool->tp_index = 0;  
  216.   
  217.     sp_thread_mutex_destroy( &pool->tp_mutex );  
  218.     sp_thread_cond_destroy( &pool->tp_idle );  
  219.     sp_thread_cond_destroy( &pool->tp_full );  
  220.     sp_thread_cond_destroy( &pool->tp_empty );  
  221.   
  222.     free( pool->tp_list );  
  223.     free( pool );  
  224. }  

[cpp]  view plain copy
  1. /** 
  2.  * threadpool_test.c 
  3.  * 
  4.  * Just a regression test for the threadpool code. 
  5.  */  
  6.   
  7. #include <stdio.h>  
  8. #include <stdlib.h>  
  9. #include <errno.h>  
  10. #include <stdarg.h>  
  11. #include "ThreadPool.h"  
  12.   
  13. #include "spthread.h"  
  14.   
  15. extern int errno;  
  16.   
  17. void mylog( FILE * fp, const  char  *format,  /*args*/ ...)  
  18. {  
  19.     va_list ltVaList;  
  20.     va_start( ltVaList, format );  
  21.     vprintf( format, ltVaList );  
  22.     va_end( ltVaList );  
  23.   
  24.     fflush( stdout );  
  25. }  
  26.   
  27. void dispatch_threadpool_to_me(void *arg) {  
  28.   int seconds = (int) arg;  
  29.   
  30.   fprintf(stdout, "  in dispatch_threadpool %d\n", seconds);  
  31.   fprintf(stdout, "  thread#%ld\n", sp_thread_self() );  
  32.   sp_sleep(seconds);  
  33.   fprintf(stdout, "  done dispatch_threadpool %d\n", seconds);  
  34. }  
  35.   
  36. int main(int argc, char **argv) {  
  37.   threadpool tp;  
  38.   
  39.   tp = create_threadpool(2);  
  40.   fprintf(stdout, "create thread over...\n");  
  41.   
  42.   fprintf(stdout, "**main** dispatch_threadpool 3\n");  
  43.   dispatch_threadpool(tp, dispatch_threadpool_to_me, (void *) 3);  
  44.   fprintf(stdout, "**main** dispatch_threadpool 6\n");  
  45.   dispatch_threadpool(tp, dispatch_threadpool_to_me, (void *) 6);  
  46.   fprintf(stdout, "**main** dispatch_threadpool 7\n");  
  47.   dispatch_threadpool(tp, dispatch_threadpool_to_me, (void *) 7);  
  48.   
  49.   fprintf(stdout, "**main** done first\n");  
  50.   sp_sleep(20);  
  51.   fprintf(stdout, "\n\n");  
  52.   
  53.   fprintf(stdout, "**main** dispatch_threadpool 3\n");  
  54.   dispatch_threadpool(tp, dispatch_threadpool_to_me, (void *) 3);  
  55.   fprintf(stdout, "**main** dispatch_threadpool 6\n");  
  56.   dispatch_threadpool(tp, dispatch_threadpool_to_me, (void *) 6);  
  57.   fprintf(stdout, "**main** dispatch_threadpool 7\n");  
  58.   dispatch_threadpool(tp, dispatch_threadpool_to_me, (void *) 7);  
  59.   
  60.   fprintf(stdout, "**main done second\n");  
  61.   
  62.   destroy_threadpool( tp );  
  63.   
  64.   //sp_sleep(20);  
  65.   return -1;  
  66. }  

转载注释: 线程池维持一个指针数组 tp_list,并用tp_index表示线程池中空闲线程的数量,tp_count表示线程池开辟的线程总数,当0==tp_index时,说明线程池中没有空闲的线程,此时如果有任务投递进来,当tp_count >= tp_max_index则通过等待空闲线程信号sp_thread_cond_wait( &pool->tp_idle, &pool->tp_mutex );  来等待线程池出现空闲线程;当tp_count < tp_max_index时,则开辟新线程执行任务。当0 < tp_index时,说明线程池中存在空闲线程,则取出末端线程资源执行投递任务
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值