Linux网络编程 - TCP Socket 简单练习:线程池实现并发服务器



服务器函数执行流程

main

init_system

creat_pthread_pool

child_work


thread_manager


task_manager

process_client


monitor


sys_clean


Makefile文件

[plain]  view plain  copy
 print ?
  1. CC = gcc  
  2. TARGET = pthread_pool  
  3. SRC = pthread_pool.c base.c  
  4. OBJECT = pthread_pool.o  base.o  
  5. INCLUDES = -I./  
  6. LDFLAGS = -lpthread  
  7.   
  8. all:$(TARGET)  
  9.   
  10. $(OBJECT):$(SRC)  
  11.     $(CC) -c $(INCLUDES) ${SRC}  
  12.   
  13. $(TARGET):$(OBJECT)  
  14.     $(CC) -o $@ $(OBJECT) $(LDFLAGS)  
  15.   
  16. .PHONY:clean  
  17.   
  18. clean:  
  19.     @rm -rf $(OBJECT) $(TARGET) *~  

服务器代码

头文件

[cpp]  view plain  copy
 print ?
  1. #ifndef __PTHREAD_POOL_H__  
  2.   
  3. #define __PTHREAD_POOL_H__  
  4.   
  5. #include   
  6. #include   
  7. #include   
  8. #include   
  9. #include   
  10. #include   
  11. #include   
  12. #include   
  13. #include   
  14. #include   
  15. #include   
  16. #include   
  17. #include   
  18. #include   
  19. #include   
  20. #include   
  21. #include   
  22. #include   
  23.   
  24. #define THREAD_MAX_NUM  100     /* max number of thread. */  
  25. #define THREAD_DEF_NUM  20      /* by default ,number of thread. */  
  26. #define THREAD_MIN_NUM  5       /* min number of thread pool. */  
  27. #define LISNUM  5  
  28. #define PORT    9001  
  29. #define MAXBUF  1024  
  30.   
  31.   
  32. /* 
  33.  * *ds of the every task. make all task in a single link 
  34.  */  
  35. //任务结构节点,用于描述每个任务的具体属性  
  36. typedef struct task_node  
  37. {  
  38.     void *arg;                              /* fun arg. */  
  39.     void *(*fun)(void *);                   /* the real work of the task. */  
  40.     pthread_t       tid;            /* which thread exec this task. */  
  41.     int         work_id;        /* task id. */  
  42.     int         flag;           /* 1: assigned, 0: unassigned. */  
  43.     struct task_node    *next;  
  44.     pthread_mutex_t     mutex;          /* when modify this ds and exec the work,lock the task ds. */  
  45. } TASK_NODE;  
  46.   
  47.   
  48. /* 
  49.  * *the ds  of the task_queue 
  50.  */  
  51. //任务队列结构,用于控制整个任务队列  
  52. typedef struct task_queue  
  53. {  
  54.     pthread_mutex_t     mutex;  
  55.     pthread_cond_t      cond;   /* when no task, the manager thread wait for ;when a new task come, signal. */  
  56.     struct task_node    *head;  /* point to the task_link. */  
  57.     int         number; /* current number of task, include unassinged and assigned but no finished. */  
  58. } TASK_QUEUE_T;  
  59.   
  60.   
  61. /* 
  62.  * *the ds of every thread, make all thread in a double link queue. 
  63.  */  
  64. //线程结构节点,用于描述每个线程的具体属性  
  65. typedef struct pthread_node  
  66. {  
  67.     pthread_t       tid;    /* the pid of this thread in kernel,the value is  syscall return . */  
  68.     int         flag;   /*  1:busy, 0:free. */  
  69.     struct task_node    *work;  /*  if exec a work, which work. */  
  70.     struct pthread_node *next;  
  71.     struct pthread_node *prev;  
  72.     pthread_cond_t      cond;   /* when assigned a task, signal this child thread by manager. */  
  73.     pthread_mutex_t     mutex;  
  74. } THREAD_NODE;  
  75.   
  76.   
  77. /* 
  78.  * *the ds of the thread queue 
  79.  */  
  80. //线程队列结构,用于控制空闲线程队列和忙碌线程队列  
  81. typedef struct pthread_queue  
  82. {  
  83.     int         number; /* the number of thread in this queue. */  
  84.     struct pthread_node *head;  
  85.     struct pthread_node *rear;  
  86.     pthread_cond_t      cond;   /* when no idle thread, the manager wait for ,or when a thread return with idle, signal. */  
  87.     pthread_mutex_t     mutex;  
  88. } PTHREAD_QUEUE_T;  
  89.   
  90. //在pthread_poll()中定义的三个结构的指针  
  91. extern PTHREAD_QUEUE_T  *pthread_queue_idle;    /* the idle thread double link queue. */  
  92. extern PTHREAD_QUEUE_T  *pthread_queue_busy;    /* the work thread double link queue. */  
  93. extern TASK_QUEUE_T *task_queue_head;       /* the task queuee single link list. */  
  94.   
  95. void *child_work( void *ptr );  
  96.   
  97. void create_pthread_pool( void );  
  98.   
  99. void init_system( void );  
  100.   
  101. void *thread_manager( void *ptr );  
  102.   
  103. void *prcoess_client( void *ptr );  
  104.   
  105. void *task_manager( void *ptr );  
  106.   
  107. void *monitor( void *ptr );  
  108.   
  109. void sys_clean( void );  
  110.   
  111. #endif  

基础函数

[cpp]  view plain  copy
 print ?
  1. #include "pthread_pool.h"  
  2.   
  3.   
  4. /* 
  5.  * *child_work:the code exec in child thread 
  6.  * *ptr: the ds of thread_node of current thread. 
  7.  * *return :nothing.void * just avoid warning. 
  8.  */  
  9. /* 
  10.     child_work为创建的线程执行的函数 
  11.     主要用来等待线程属性状态的变化,来判断是否有任务要执行 
  12.     并且判断线程的工作状态的变化,来决定加入哪个线程队列(空闲还是忙碌) 
  13. */  
  14. void *  
  15. child_work( void *ptr )  
  16. {  
  17.     //这里的ptr为(void *) &temp[i]  
  18.     THREAD_NODE * self = (THREAD_NODE *) ptr;  
  19.   
  20.     /*modify the tid attribute the first time exec */  
  21.     pthread_mutex_lock( &self->mutex );  
  22.     self->tid = syscall( SYS_gettid );//获得线程自身id  
  23.     pthread_mutex_unlock( &self->mutex );  
  24.   
  25.     while ( 1 )  
  26.     {  
  27.         pthread_mutex_lock( &self->mutex );  
  28.   
  29.         /*if no task exec,blocked */  
  30.         /*  
  31.             关键的一句话 
  32.             从线程的属性struct task_node *work(即为self->work) 
  33.             判断是否已给当前线程分配任务 
  34.         */  
  35.         //如果该线程尚没有分配任务,则通过条件变量阻塞等待条件变量self->cond  
  36.         if ( NULL == self->work )   
  37.         {  
  38.             pthread_cond_wait( &self->cond, &self->mutex );  
  39.         }  
  40.   
  41.         pthread_mutex_lock( &self->work->mutex );  
  42.   
  43.         /*execute the real work.  
  44.             开始执行任务 
  45.         */  
  46.         self->work->fun( self->work->arg );  
  47.   
  48.         /*after finished the work  
  49.             任务执行完后,撤销任务的属性,并销毁任务本身,释放其占用的资源 
  50.         */  
  51.         self->work->fun       = NULL;  
  52.         self->work->flag  = 0;  
  53.         self->work->tid       = 0;  
  54.         self->work->next  = NULL;  
  55.   
  56.         free( self->work->arg );  
  57.   
  58.         pthread_mutex_unlock( &self->work->mutex ); /* unlock the task */  
  59.         pthread_mutex_destroy( &self->work->mutex );  
  60.   
  61.         /*free the task space */  
  62.         free( self->work );  
  63.   
  64.         /*make self thread no work */  
  65.         self->work   = NULL;  
  66.         self->flag   = 0;  
  67.   
  68.   
  69.         /* 
  70.          * *get new task from the task_link if not NULL. 
  71.          * *there no idle thread if there are task to do. 
  72.          * *if on task ,make self idle and add to the idle queue. 
  73.          */  
  74.         /* 
  75.             执行完上一个任务后,查看任务队列中是否还有任务      
  76.         */  
  77.         pthread_mutex_lock( &task_queue_head->mutex );  
  78.         if ( task_queue_head->head != NULL )//如果有任务,则分配任务  
  79.         {  
  80.             TASK_NODE * temp = task_queue_head->head;  
  81.   
  82.             /*get the first task */  
  83.             task_queue_head->head = task_queue_head->head->next;  
  84.   
  85.             /*modify self thread attribute */  
  86.             self->flag   = 1;  
  87.             self->work   = temp;  
  88.             temp->tid    = self->tid;  
  89.             temp->next   = NULL;  
  90.             temp->flag   = 1;  
  91.   
  92.             task_queue_head->number--;  
  93.   
  94.             pthread_mutex_unlock( &task_queue_head->mutex );  
  95.   
  96.             pthread_mutex_unlock( &self->mutex );  
  97.   
  98.             continue;  
  99.         }  
  100.         else //如果没有任务,从忙碌线程队列中删除此线程,将其加入空闲线程队列中    
  101.         {  
  102.             /*no task need to exec, add self to idle queue and del from busy queue */  
  103.             pthread_mutex_unlock( &task_queue_head->mutex );  
  104.   
  105.             pthread_mutex_lock( &pthread_queue_busy->mutex );  
  106.   
  107.             /*self is the last execte thread  
  108.                 如果此线程是忙碌的线程队列中的仅剩的一个线程 
  109.             */  
  110.             if ( pthread_queue_busy->head == self  
  111.                  && pthread_queue_busy->rear == self )  
  112.             {  
  113.                 pthread_queue_busy->head = pthread_queue_busy->rear = NULL;  
  114.                 self->next           = self->prev = NULL;  
  115.             }  
  116.             /*the first one thread in busy queue  
  117.                 如果此线程是忙碌的线程队列中的第一个线程 
  118.             */  
  119.             else if ( pthread_queue_busy->head == self  
  120.                   && pthread_queue_busy->rear != self )  
  121.             {  
  122.                 pthread_queue_busy->head = pthread_queue_busy->head->next;  
  123.                 pthread_queue_busy->head->prev    = NULL;  
  124.   
  125.                 self->next = self->prev = NULL;  
  126.             }  
  127.             /*the last one thread in busy queue  
  128.                 如果此线程是忙碌的线程队列中的末尾的一个线程 
  129.             */  
  130.             else if ( pthread_queue_busy->head != self  
  131.                   && pthread_queue_busy->rear == self )  
  132.             {  
  133.                 pthread_queue_busy->rear = pthread_queue_busy->rear->prev;  
  134.                 pthread_queue_busy->rear->next    = NULL;  
  135.   
  136.                 self->next = self->prev = NULL;  
  137.             }  
  138.             /*middle one  
  139.                 如果此线程是忙碌的线程队列中的中间的某个线程 
  140.             */  
  141.             else{  
  142.                 self->next->prev  = self->prev;  
  143.                 self->prev->next  = self->next;  
  144.                 self->next       = self->prev = NULL;  
  145.             }  
  146.   
  147.             pthread_mutex_unlock( &pthread_queue_busy->mutex );  
  148.   
  149.             /*add self to the idle queue  
  150.                 将此线程加入空闲线程队列中 
  151.             */  
  152.             pthread_mutex_lock( &pthread_queue_idle->mutex );  
  153.   
  154.             /*now the idle queue is empty  
  155.                 判断空闲线程队列的情况,根据不同的情况将此线程加入不同的位置 
  156.             */  
  157.             if ( pthread_queue_idle->head == NULL  
  158.                  || pthread_queue_idle->rear == NULL )  
  159.             {  
  160.                 pthread_queue_idle->head = pthread_queue_idle->rear = self;  
  161.                 self->next           = self->prev = NULL;  
  162.             }else  {  
  163.                 self->next       = pthread_queue_idle->head;  
  164.                 self->prev       = NULL;  
  165.                 self->next->prev  = self;  
  166.   
  167.                 pthread_queue_idle->head = self;  
  168.                 pthread_queue_idle->number++;  
  169.             }  
  170.   
  171.             pthread_mutex_unlock( &pthread_queue_idle->mutex );  
  172.   
  173.             pthread_mutex_unlock( &self->mutex );  
  174.   
  175.             /*signal have idle thread  
  176.                 告知阻塞等待条件变量pthread_queue_idle->cond的位置已有空闲线程 
  177.             */  
  178.             pthread_cond_signal( &pthread_queue_idle->cond );  
  179.         }  
  180.     }  
  181. }  
  182.   
  183.   
  184. /* 
  185.  * *create thread pool when the system on, and thread number is THREAD_DEF_NUM. 
  186.  * *when init, initial all the thread into a double link queue and all wait fo self->cond. 
  187.  */  
  188. void  
  189. create_pthread_pool( void )  
  190. {  
  191.     //分配线程节点  
  192.     THREAD_NODE * temp =  
  193.         (THREAD_NODE *) malloc( sizeof(THREAD_NODE) * THREAD_DEF_NUM );  
  194.   
  195.     if ( temp == NULL )  
  196.     {  
  197.         printf( " malloc failure\n" );  
  198.         exit( EXIT_FAILURE );  
  199.     }  
  200.   
  201.     /*init as a double link queue  
  202.         初始化为双向链式队列 
  203.     */  
  204.     int i;  
  205.   
  206.     //THREAD_DEF_NUM为线程池中线程的最大数量  
  207.     //for循环开始创建线程池  
  208.     for ( i = 0; i < THREAD_DEF_NUM; i++ )  
  209.     {  
  210.         temp[i].tid     = i + 1;  
  211.         temp[i].work    = NULL;  
  212.         temp[i].flag    = 0;  
  213.   
  214.         if ( i == THREAD_DEF_NUM - 1 )  
  215.             temp[i].next = NULL;  
  216.   
  217.         if ( i == 0 )  
  218.             temp[i].prev = NULL;  
  219.   
  220.         //双向链表的体现  
  221.         temp[i].prev    = &temp[i - 1];  
  222.         temp[i].next    = &temp[i + 1];  
  223.   
  224.         pthread_cond_init( &temp[i].cond, NULL );  
  225.         pthread_mutex_init( &temp[i].mutex, NULL );  
  226.   
  227.         /*create this thread  
  228.             在此创建线程,各个线程执行的函数为child_work 
  229.         */  
  230.         pthread_create( &temp[i].tid, NULL, child_work, (void *) &temp[i] );  
  231.     }  
  232.   
  233.     /*modify the idle thread queue attribute  
  234.         修改空闲线程队列的属性 
  235.     */  
  236.     pthread_mutex_lock( &pthread_queue_idle->mutex );  
  237.   
  238.     pthread_queue_idle->number   = THREAD_DEF_NUM;  
  239.     //此句就将刚创建的那些线程给空闲线程队列  
  240.     pthread_queue_idle->head = &temp[0];  
  241.     pthread_queue_idle->rear = &temp[THREAD_DEF_NUM - 1];  
  242.   
  243.     pthread_mutex_unlock( &pthread_queue_idle->mutex );  
  244. }  
  245.   
  246.   
  247. /* 
  248.  * *init_system :init the system glob pointor. 
  249.  */  
  250. void  
  251. init_system( void )  
  252. {  
  253.     /*init the pthread_queue_idle  
  254.         初始化空闲线程队列,采用的是普通的双向链式结构(未循环) 
  255.     */  
  256.     pthread_queue_idle =  
  257.         (PTHREAD_QUEUE_T *) malloc( sizeof(PTHREAD_QUEUE_T) );  
  258.   
  259.     pthread_queue_idle->number   = 0;  
  260.     pthread_queue_idle->head = NULL;  
  261.     pthread_queue_idle->rear = NULL;  
  262.     pthread_mutex_init( &pthread_queue_idle->mutex, NULL );  
  263.     pthread_cond_init( &pthread_queue_idle->cond, NULL );  
  264.   
  265.     /*init the pthread_queue_busy  
  266.         初始化空闲线程队列,采用的是普通的双向链式结构(未循环) 
  267.     */  
  268.     pthread_queue_busy =  
  269.         (PTHREAD_QUEUE_T *) malloc( sizeof(PTHREAD_QUEUE_T) );  
  270.   
  271.     pthread_queue_busy->number   = 0;  
  272.     pthread_queue_busy->head = NULL;  
  273.     pthread_queue_busy->rear = NULL;  
  274.     pthread_mutex_init( &pthread_queue_busy->mutex, NULL );  
  275.     pthread_cond_init( &pthread_queue_busy->cond, NULL );  
  276.   
  277.     /*init the task_queue_head  
  278.         初始化任务队列,采用单向链表 
  279.     */  
  280.     task_queue_head = (TASK_QUEUE_T *) malloc( sizeof(TASK_QUEUE_T) );  
  281.   
  282.     task_queue_head->head    = NULL;  
  283.     task_queue_head->number = 0;  
  284.     pthread_cond_init( &task_queue_head->cond, NULL );  
  285.     pthread_mutex_init( &task_queue_head->mutex, NULL );  
  286.   
  287.     /*create thread poll  
  288.         创建线程池 
  289.     */  
  290.     create_pthread_pool();  
  291. }  
  292.   
  293.   
  294. /* 
  295.  * *thread_manager:code exec in manager thread. 
  296.  *               block on task_queue_head->cond when no task come. 
  297.  *               block on pthread_queue_idle->cond when no idle thread 
  298.  **ptr:no used ,in order to avoid warning. 
  299.  **return :nothing. 
  300.  */  
  301.   
  302. void *  
  303. thread_manager( void *ptr )  
  304. {  
  305.     while ( 1 )  
  306.     {  
  307.         THREAD_NODE * temp_thread   = NULL;  
  308.         TASK_NODE   * temp_task = NULL;  
  309.   
  310.         /* 
  311.          * *get a new task, and modify the task_queue. 
  312.          * *if no task block om task_queue_head->cond. 
  313.          */  
  314.         pthread_mutex_lock( &task_queue_head->mutex );  
  315.         //如果任务队列为空,则阻塞等待条件变量task_queue_head->cond  
  316.         if ( task_queue_head->number == 0 )  
  317.             pthread_cond_wait( &task_queue_head->cond,  
  318.                        &task_queue_head->mutex );  
  319.   
  320.         //如果不为空,则开始准备分配任务,并修改任务队列属性  
  321.         temp_task       = task_queue_head->head;  
  322.         task_queue_head->head    = task_queue_head->head->next;  
  323.         task_queue_head->number--;  
  324.   
  325.         pthread_mutex_unlock( &task_queue_head->mutex );  
  326.   
  327.   
  328.         /* 
  329.          * *get a new idle thread, and modify the idle_queue. 
  330.          * *if no idle thread, block on pthread_queue_idle->cond. 
  331.          */  
  332.         //有了任务之后,开始判断是否有空闲线程  
  333.         pthread_mutex_lock( &pthread_queue_idle->mutex );  
  334.           
  335.         //如果没有空闲线程,则阻塞等待条件变量pthread_queue_idle->cond  
  336.         if ( pthread_queue_idle->number == 0 )  
  337.             pthread_cond_wait( &pthread_queue_idle->cond,  
  338.                        &pthread_queue_idle->mutex );  
  339.                          
  340.         //如果有空闲线程则取出一个空闲线程,然后修改空闲线程队列属性  
  341.         temp_thread = pthread_queue_idle->head;  
  342.   
  343.         /*if this is the last idle thread ,modiry the head and rear pointor */  
  344.         if ( pthread_queue_idle->head == pthread_queue_idle->rear )  
  345.         {  
  346.             pthread_queue_idle->head = NULL;  
  347.             pthread_queue_idle->rear = NULL;  
  348.         }  
  349.         /*if idle thread number>2, get the first one,modify the head pointor  */  
  350.         else{  
  351.             pthread_queue_idle->head = pthread_queue_idle->head->next;  
  352.             pthread_queue_idle->head->prev    = NULL;  
  353.         }  
  354.   
  355.         pthread_queue_idle->number--;//将空闲线程队列数量减一  
  356.   
  357.         pthread_mutex_unlock( &pthread_queue_idle->mutex );  
  358.   
  359.         /*modify the  task attribute.  
  360.             修改取出的线程的线程结构属性和相关的任务结构属性 
  361.         */  
  362.         pthread_mutex_lock( &temp_task->mutex );  
  363.   
  364.         temp_task->tid   = temp_thread->tid;  
  365.         temp_task->next = NULL;  
  366.         temp_task->flag = 1;  
  367.   
  368.         pthread_mutex_unlock( &temp_task->mutex );  
  369.   
  370.         /*modify the idle thread attribute. */  
  371.         pthread_mutex_lock( &temp_thread->mutex );  
  372.   
  373.         temp_thread->flag    = 1;  
  374.         temp_thread->work    = temp_task;  
  375.         temp_thread->next    = NULL;  
  376.         temp_thread->prev    = NULL;  
  377.   
  378.         pthread_mutex_unlock( &temp_thread->mutex );  
  379.   
  380.         /*add the thread assinged task to the busy queue. */  
  381.         //将已分配任务的线程加入忙碌线程队列中  
  382.         pthread_mutex_lock( &pthread_queue_busy->mutex );  
  383.   
  384.         /*if this is the first one in busy queue */  
  385.         if ( pthread_queue_busy->head == NULL )  
  386.         {  
  387.             pthread_queue_busy->head = temp_thread;  
  388.             pthread_queue_busy->rear = temp_thread;  
  389.             temp_thread->prev        = temp_thread->next = NULL;  
  390.         }else  {  
  391.             /*insert in thre front of the queue */  
  392.             pthread_queue_busy->head->prev    = temp_thread;  
  393.             temp_thread->prev        = NULL;  
  394.             temp_thread->next        = pthread_queue_busy->head;  
  395.             pthread_queue_busy->head = temp_thread;  
  396.             pthread_queue_busy->number++;  
  397.         }  
  398.         pthread_mutex_unlock( &pthread_queue_busy->mutex );  
  399.   
  400.         /*signal the child thread to exec the work */  
  401.         //告知阻塞等待条件变量temp_thread->cond的位置,开始执行任务  
  402.         pthread_cond_signal( &temp_thread->cond );  
  403.     }  
  404. }  
  405.   
  406.   
  407. /* 
  408.  * *code to process the new client in every chilld pthead. 
  409.  * *ptr: the fd come from listen thread that can communicate to the client. 
  410.  * *return:nothing. void * only used to avoid waring. 
  411.  */  
  412. //用来处理任务的函数  
  413. void *  
  414. prcoess_client( void *ptr )  
  415. {  
  416.     int net_fd;  
  417.     net_fd = atoi( (char *) ptr );  
  418.   
  419.     socklen_t   len;  
  420.     char        buf[MAXBUF + 1];  
  421.     /*下面是select用到的变量的定义 */  
  422.     fd_set      rfds;  
  423.     struct timeval  tv;  
  424.     int     retval;  
  425.     int     maxfd = -1;  
  426.   
  427.     while ( 1 )  
  428.     {  
  429.         FD_ZERO( &rfds );                                                       /* 初始化rfds为空 */  
  430.         FD_SET( 0, &rfds );                                                     /* 将标准输入的描述符0加入到集合rfds中 */  
  431.         FD_SET( net_fd, &rfds );                                                /* 将net_fd加入到集合rfds中 */  
  432.         maxfd       = net_fd + 1;  
  433.         tv.tv_sec   = 1;                                                    /* 阻塞等待时间为1s */  
  434.         tv.tv_usec  = 0;  
  435.   
  436.         retval = select( maxfd, &rfds, NULL, NULL, &tv );                       /* 多路复用,同时监测描述符0和net_fd */  
  437.         if ( retval == -1 )                                                     /* select函数执行出错 */  
  438.         {  
  439.             perror( "select" );  
  440.             exit( EXIT_FAILURE );  
  441.         }else if ( retval == 0 )                                                /* select函数执行超时 */  
  442.             continue;  
  443.         else/*有描述符引起异常 */  
  444.             if ( FD_ISSET( 0, &rfds ) )                                     /* 判断是不是标准输入0引起的异常 */  
  445.             {  
  446.                 bzero( buf, sizeof(buf) );                              /* 清空buf */  
  447.                 fgets( buf, sizeof(buf) - 1, stdin );                   /* 从终端接收输入 */  
  448.   
  449.                 if ( !strncasecmp( buf, "quit", 4 ) )                   /* 判断是否为退出 */  
  450.                 {  
  451.                     printf( "i will close the connect!\n" );  
  452.                     close( net_fd );  
  453.                     goto clean;  
  454.                 }  
  455.   
  456.                 len = send( net_fd, buf, strlen( buf ) - 1, 0 );        /* 向客户端发送消息 */  
  457.                 if ( len > 0 )  
  458.                 {  
  459.                     printf( "send successful,%d byte send!\n", len );  
  460.                 }else  {  
  461.                     printf( "message '%s' send failure !\n", buf );  
  462.                     printf( "errno code is %d, errno message is '%s'\n", errno, strerror( errno ) );  
  463.                     close( net_fd );  
  464.                     goto clean;  
  465.                 }  
  466.             }  
  467.   
  468.             if ( FD_ISSET( net_fd, &rfds ) )                        /* 判断是不是net_fd引起的异常 */  
  469.             {  
  470.                 bzero( buf, sizeof(buf) );  
  471.                 len = recv( net_fd, buf, sizeof(buf) - 1, 0 );  /* 从客户端接收消息 */  
  472.                 if ( len > 0 )  
  473.                     printf( "message recv successful : '%s', %d Byte recv\n", buf, len );  
  474.                 else if ( len < 0 )  
  475.                 {  
  476.                     printf( "recv failure !\nerrno code is %d, errno message is '%s'\n", errno, strerror( errno ) );  
  477.                     close( net_fd );  
  478.                     goto clean;  
  479.                 }else  { /* 如果客户端已关闭 */  
  480.                     printf( "the other one close quit\n" );  
  481.                     close( net_fd );  
  482.                     return;  
  483.                 }  
  484.             }  
  485.         }  
  486.     }  
  487.     close( net_fd );  
  488.     return;  
  489.   
  490. clean:  
  491.     sys_clean();  
  492. }  
  493.   
  494.   
  495. /* 
  496.  * *task_manager: get new task and add to the tail of the task_link. 
  497.  * *ptr: no used. just avoid warning. 
  498.  * *return:nothing. 
  499.  */  
  500. //用来监听客户端的连接,产生任务  
  501. void *  
  502. task_manager( void *ptr )  
  503. {  
  504.     int listen_fd;  
  505.   
  506.     if ( -1 == (listen_fd = socket( AF_INET, SOCK_STREAM, 0 ) ) )  
  507.     {  
  508.         perror( "socket" );  
  509.         goto clean;  
  510.     }  
  511.   
  512.     struct ifreq ifr;  
  513.   
  514.     //eno16777736类似于eth0,在Linux系统中可以修改为eth0  
  515.     strcpy( ifr.ifr_name, "eno16777736" );  
  516.     //获取eno16777736的ip地址  
  517.     if ( ioctl( listen_fd, SIOCGIFADDR, &ifr ) < 0 )  
  518.     {  
  519.         perror( "ioctl" );  
  520.         goto clean;  
  521.     }  
  522.   
  523.     struct sockaddr_in myaddr;  
  524.   
  525.     myaddr.sin_family   = AF_INET;  
  526.     myaddr.sin_port     = htons( PORT );//PORT为9001,在头文件中设置,是全局变量  
  527.     myaddr.sin_addr.s_addr  =  
  528.         ( (struct sockaddr_in *) &(ifr.ifr_addr) )->sin_addr.s_addr;  
  529.   
  530. "white-space:pre">    //输出ip和port信息  
  531. "white-space:pre">    printf("server_ip = %s\nserver_port = %d\nlisnum = %d\n", inet_ntoa(myaddr.sin_addr), PORT, LISNUM);  
  532.   
  533.     //绑定IP地址和端口port  
  534.     if ( -1 == bind( listen_fd, (struct sockaddr *) &myaddr, sizeof(myaddr) ) )  
  535.     {  
  536.         perror( "bind" );  
  537.         goto clean;  
  538.     }  
  539.     //监听  
  540.     if ( -1 == listen( listen_fd, 5 ) )  
  541.     {  
  542.         perror( "listen" );  
  543.         goto clean;  
  544.     }  
  545.   
  546.     /*i is the id of the task */  
  547.     int i;  
  548.     //开始接受客户端的连接,产生任务  
  549.     for ( i = 1; ; i++ )  
  550.     {  
  551.         int newfd;  
  552.         struct sockaddr_in  client;  
  553.         socklen_t len = sizeof(client);  
  554.   
  555.         if ( -1 ==  
  556.              (newfd = accept( listen_fd, (struct sockaddr *) &client, &len ) ) )  
  557.         {  
  558.             perror( "accept" );  
  559.             goto clean;  
  560.         }  
  561.         /* 打印本次连接的客户端的地址信息 inet_ntoa  ntohs */  
  562.         printf( "server: got connection from %s, port %d, socket %d\n", inet_ntoa( client.sin_addr ), ntohs( client.sin_port ), newfd );  
  563.   
  564.         //开始将产生的新任务加入任务队列之中  
  565.         TASK_NODE   * temp      = NULL;  
  566.         TASK_NODE   * newtask   = (TASK_NODE *) malloc( sizeof(TASK_NODE) );  
  567.         if ( newtask == NULL )  
  568.         {  
  569.             printf( "malloc error" );  
  570.             goto clean;  
  571.         }  
  572.   
  573.         /* 
  574.          * *initial the attribute of the task. 
  575.          * *because this task havn't add to system,so,no need lock the mutex. 
  576.          */  
  577.   
  578.         newtask->arg = (void *) malloc( 128 );  
  579.   
  580.         memset( newtask->arg, '\0', 128 );  
  581.         //任务执行的参数为连接的客户端的socket描述符  
  582.         sprintf( newtask->arg, "%d", newfd );  
  583.         //新任务的处理函数均为prcoess_client,newfd即为函数prcoess_client的参数  
  584.         newtask->fun     = prcoess_client;  
  585.         newtask->tid     = 0;  
  586.         newtask->work_id = i;  
  587.         newtask->next        = NULL;  
  588.         pthread_mutex_init( &newtask->mutex, NULL );  
  589.   
  590.         /*add new task to task_link */  
  591.         pthread_mutex_lock( &task_queue_head->mutex );  
  592.   
  593.         /*find the tail of the task link and add the new one to tail  
  594.             开始将产生的新任务加入到任务队列中 
  595.         */  
  596.         temp = task_queue_head->head;  
  597.   
  598.         if ( temp == NULL )  
  599.         {  
  600.             task_queue_head->head = newtask;  
  601.         }else  {  
  602.             while ( temp->next != NULL )  
  603.                 temp = temp->next;  
  604.   
  605.             temp->next = newtask;  
  606.         }  
  607.         task_queue_head->number++;//任务队列数量加一  
  608.   
  609.         pthread_mutex_unlock( &task_queue_head->mutex );  
  610.   
  611.         /*signal the manager thread , task coming  
  612.             告知阻塞等待条件变量task_queue_head->cond的位置,已有未执行的任务 
  613.         */  
  614.         pthread_cond_signal( &task_queue_head->cond );  
  615.     }  
  616.   
  617.     return;  
  618.   
  619. clean:  
  620.     sys_clean();  
  621. }  
  622.   
  623.   
  624. /* 
  625.  * *monitor: get the system info 
  626.  * *ptr: not used ,only to avoid warning for pthread_create 
  627.  * *return: nothing. 
  628.  */  
  629. //用来输出哪些线程在工作  
  630. void *  
  631. monitor( void *ptr )  
  632. {  
  633.     /*in order to prevent warning. */  
  634.     ptr = ptr;  
  635.   
  636.     THREAD_NODE * temp_thread = NULL;  
  637.   
  638.     while ( 1 )  
  639.     {  
  640.         pthread_mutex_lock( &pthread_queue_busy->mutex );  
  641.   
  642.         /*output the busy thread works one by one */  
  643.         temp_thread = pthread_queue_busy->head;  
  644.   
  645.         printf( "\n*******************************\n" );  
  646.         while ( temp_thread )  
  647.         {  
  648.             printf( "thread %ld is  execute work_number %d\n",           \  
  649.                 temp_thread->tid, temp_thread->work->work_id );  
  650.             temp_thread = temp_thread->next;  
  651.         }  
  652.         printf( "*******************************\n\n" );  
  653.   
  654.         pthread_mutex_unlock( &pthread_queue_busy->mutex );  
  655.   
  656.         sleep( 10 );  
  657.     }  
  658.   
  659.     return;  
  660. }  
  661.   
  662.   
  663. /* 
  664.  * *sys_clean: clean the system . 
  665.  * *this function code need to do to make it more stronger. 
  666.  */  
  667. //清理函数  
  668. void  
  669. sys_clean( void )  
  670. {  
  671.     printf( "the system exit abnormally\n" );  
  672.     exit( EXIT_FAILURE );  
  673. }  

主函数

[cpp]  view plain  copy
 print ?
  1. #include "pthread_pool.h"  
  2.   
  3. //定义三个结构的指针  
  4. PTHREAD_QUEUE_T * pthread_queue_idle;           /* the idle thread double link queue. */  
  5. PTHREAD_QUEUE_T *pthread_queue_busy;            /* the work thread double link queue. */  
  6. TASK_QUEUE_T    *task_queue_head;               /* the task queuee single link list. */  
  7.   
  8. int  
  9. main( int argc, char *argv[] )  
  10. {  
  11.     pthread_t thread_manager_tid, task_manager_tid, monitor_id;  
  12.   
  13.     //初始化空闲线程、在工作线程和要完成的任务  
  14.     init_system();  
  15.   
  16.     //创建线程池管理线程、创建任务管理线程和线程状态监视线程  
  17.     pthread_create( &thread_manager_tid, NULL, thread_manager, NULL );      /* create thread to manage the thread pool. */  
  18.     pthread_create( &task_manager_tid, NULL, task_manager, NULL );          /* create thread recive task from client. */  
  19.     pthread_create( &monitor_id, NULL, monitor, NULL );                     /* create thread to monitor the system info. */  
  20.   
  21.     //等待线程退出  
  22.     pthread_join( thread_manager_tid, NULL );  
  23.     pthread_join( task_manager_tid, NULL );  
  24.     pthread_join( monitor_id, NULL );  
  25.   
  26.     //清理服务器,准备退出主函数  
  27.     sys_clean();  
  28.   
  29.     return(0);  
  30. }  

客户端代码

[cpp]  view plain  copy
 print ?
  1. /************************************************************************* 
  2.     > File Name: socket_select_client.c 
  3.     > Author: genglut 
  4.     > Mail: [email protected] 
  5.     > Created Time: 2014年12月22日 星期一 18时06分06秒 
  6.  ************************************************************************/  
  7.   
  8. #include   
  9. #include   
  10. #include   
  11. #include   
  12. #include   
  13. #include   
  14. #include   
  15. #include   
  16. #include   
  17.   
  18. #define MAXBUF 1024  
  19.   
  20. int main(int argc, char *argv[])  
  21. {  
  22.     int sockfd;  
  23.     socklen_t len;  
  24.     struct sockaddr_in server_addr;  
  25.     char buf[MAXBUF + 1];  
  26.   
  27.     //下面是select用到的变量的定义  
  28.     fd_set rfds;  
  29.     struct timeval tv;  
  30.     int retval;  
  31.     int maxfd = -1;  
  32.       
  33.     if(argc != 3)  
  34.     {  
  35.         printf("error failure, it must be:\n\t\t%s IP port \n", argv[0]);  
  36.         exit(EXIT_FAILURE);  
  37.     }  
  38.   
  39.     if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)  
  40.     {  
  41.         perror("socket");  
  42.         exit(EXIT_FAILURE);  
  43.     }  
  44.   
  45.     bzero(&server_addr, sizeof(server_addr));  
  46.     server_addr.sin_family = AF_INET;  
  47.     server_addr.sin_port = htons(atoi(argv[2]));  
  48.     server_addr.sin_addr.s_addr = inet_addr(argv[1]);  
  49.   
  50.     if(connect(sockfd, (struct sockaddr *)&server_addr, sizeof(struct sockaddr)) == -1)  
  51.     {  
  52.         perror("connect");  
  53.         exit(EXIT_FAILURE);  
  54.     }  
  55.   
  56.     printf("already connected to server %s\n", argv[1]);  
  57.       
  58.       
  59.     while(1)  
  60.     {  
  61.         FD_ZERO(&rfds);//初始化rfds为空  
  62.         FD_SET(0, &rfds);//将标准输入的描述符0加入到集合rfds中  
  63.         FD_SET(sockfd, &rfds);//将newfd加入到集合rfds中  
  64.         maxfd = sockfd + 1;  
  65.         tv.tv_sec = 1;//阻塞等待时间为1s  
  66.         tv.tv_usec = 0;  
  67.           
  68.         retval = select(maxfd, &rfds, NULL, NULL, &tv);//多路复用,同时监测描述符0和newfd  
  69.           
  70.         if(retval == -1)//select函数执行出错  
  71.         {  
  72.             perror("select");  
  73.             exit(EXIT_FAILURE);  
  74.         }  
  75.         else if(retval == 0)//select函数执行超时  
  76.             continue;  
  77.         else//有描述符引起异常  
  78.         {  
  79.             if(FD_ISSET(0, &rfds))//判断是不是标准输入0引起的异常  
  80.             {  
  81.                 bzero(buf, sizeof(buf));//清空buf  
  82.                 fgets(buf, sizeof(buf)-1, stdin);//从终端接收输入  
  83.   
  84.                 if(!strncasecmp(buf, "quit", 4))//判断是否为退出  
  85.                 {  
  86.                     printf("i will quit!\n");  
  87.                     break;  
  88.                 }  
  89.                   
  90.                 len = send(sockfd, buf, strlen(buf)-1, 0);//向客户端发送消息  
  91.                 if(len > 0)  
  92.                 {  
  93.                     printf ("send successful,%d byte send!\n",len);  
  94.                 }  
  95.                 else  
  96.                 {  
  97.                     printf("message '%s' send failure !\n", buf);  
  98.                     printf("errno code is %d, errno message is '%s'\n", errno, strerror(errno));  
  99.                     break;  
  100.                 }                     
  101.             }  
  102.               
  103.             if(FD_ISSET(sockfd, &rfds))//判断是不是newfd引起的异常  
  104.             {  
  105.                 bzero(buf, sizeof(buf));  
  106.                 len = recv(sockfd, buf, sizeof(buf)-1, 0);//从客户端接收消息  
  107.                 if(len > 0 )  
  108.                     printf("message recv successful : '%s', %d Byte recv\n", buf, len);  
  109.                 else if(len < 0)  
  110.                 {  
  111.                     printf("recv failure !\nerrno code is %d, errno message is '%s'\n", errno, strerror(errno));  
  112.                     break;  
  113.                 }  
  114.                 else//如果客户端已关闭  
  115.                 {  
  116.                     printf("the other one close, quit\n");  
  117.                     break;  
  118.                 }                     
  119.             }  
  120.         }     
  121.     }  
  122.       
  123.     close(sockfd);  
  124.     printf("i quited!\n");  
  125.     return 0;  
  126. }  

运行结果

服务器:

[cpp]  view plain  copy
 print ?
  1. $ ./pthread_pool  
  2.   
  3. -----------------------------------------  
  4. -----------------------------------------  
  5.   
  6. server_ip = 172.18.229.60  
  7. server_port = 9001  
  8. lisnum = 5  
  9.   
  10. -----------------------------------------  
  11. -----------------------------------------  
  12.   
  13. server: got connection from 172.18.229.60, port 56023, socket 4  
  14. message recv successful : 'hello', 5 Byte recv  
  15.   
  16. -----------------------------------------  
  17. thread 40159 is  execute work_number 1  
  18. -----------------------------------------  
  19.   
  20. server: got connection from 172.18.229.60, port 56024, socket 5  
  21. message recv successful : 'hi', 2 Byte recv  
  22. the other one close quit  
  23.   
  24. -----------------------------------------  
  25. thread 40159 is  execute work_number 1  
  26. -----------------------------------------  
  27.   
  28. the other one close quit  

客户端1:

[cpp]  view plain  copy
 print ?
  1. $ ./client 172.18.229.60 9001  
  2. already connected to server 172.18.229.60  
  3. hello  
  4. send successful,5 byte send!  
  5. quit  
  6. i will quit!  
  7. i quited!  

客户端2:

[cpp]  view plain  copy
 print ?
  1. $ ./client 172.18.229.60 9001  
  2. already connected to server 172.18.229.60  
  3. hi  
  4. send successful,2 byte send!  
  5. quit  
  6. i will quit!  
  7. i quited!  

原文链接

http://blog.csdn.net/geng823/article/details/42144461

服务器函数执行流程

main

init_system

creat_pthread_pool

child_work


thread_manager


task_manager

process_client


monitor


sys_clean


Makefile文件

[plain]  view plain  copy
 print ?
  1. CC = gcc  
  2. TARGET = pthread_pool  
  3. SRC = pthread_pool.c base.c  
  4. OBJECT = pthread_pool.o  base.o  
  5. INCLUDES = -I./  
  6. LDFLAGS = -lpthread  
  7.   
  8. all:$(TARGET)  
  9.   
  10. $(OBJECT):$(SRC)  
  11.     $(CC) -c $(INCLUDES) ${SRC}  
  12.   
  13. $(TARGET):$(OBJECT)  
  14.     $(CC) -o $@ $(OBJECT) $(LDFLAGS)  
  15.   
  16. .PHONY:clean  
  17.   
  18. clean:  
  19.     @rm -rf $(OBJECT) $(TARGET) *~  

服务器代码

头文件

[cpp]  view plain  copy
 print ?
  1. #ifndef __PTHREAD_POOL_H__  
  2.   
  3. #define __PTHREAD_POOL_H__  
  4.   
  5. #include   
  6. #include   
  7. #include   
  8. #include   
  9. #include   
  10. #include   
  11. #include   
  12. #include   
  13. #include   
  14. #include   
  15. #include   
  16. #include   
  17. #include   
  18. #include   
  19. #include   
  20. #include   
  21. #include   
  22. #include   
  23.   
  24. #define THREAD_MAX_NUM  100     /* max number of thread. */  
  25. #define THREAD_DEF_NUM  20      /* by default ,number of thread. */  
  26. #define THREAD_MIN_NUM  5       /* min number of thread pool. */  
  27. #define LISNUM  5  
  28. #define PORT    9001  
  29. #define MAXBUF  1024  
  30.   
  31.   
  32. /* 
  33.  * *ds of the every task. make all task in a single link 
  34.  */  
  35. //任务结构节点,用于描述每个任务的具体属性  
  36. typedef struct task_node  
  37. {  
  38.     void *arg;                              /* fun arg. */  
  39.     void *(*fun)(void *);                   /* the real work of the task. */  
  40.     pthread_t       tid;            /* which thread exec this task. */  
  41.     int         work_id;        /* task id. */  
  42.     int         flag;           /* 1: assigned, 0: unassigned. */  
  43.     struct task_node    *next;  
  44.     pthread_mutex_t     mutex;          /* when modify this ds and exec the work,lock the task ds. */  
  45. } TASK_NODE;  
  46.   
  47.   
  48. /* 
  49.  * *the ds  of the task_queue 
  50.  */  
  51. //任务队列结构,用于控制整个任务队列  
  52. typedef struct task_queue  
  53. {  
  54.     pthread_mutex_t     mutex;  
  55.     pthread_cond_t      cond;   /* when no task, the manager thread wait for ;when a new task come, signal. */  
  56.     struct task_node    *head;  /* point to the task_link. */  
  57.     int         number; /* current number of task, include unassinged and assigned but no finished. */  
  58. } TASK_QUEUE_T;  
  59.   
  60.   
  61. /* 
  62.  * *the ds of every thread, make all thread in a double link queue. 
  63.  */  
  64. //线程结构节点,用于描述每个线程的具体属性  
  65. typedef struct pthread_node  
  66. {  
  67.     pthread_t       tid;    /* the pid of this thread in kernel,the value is  syscall return . */  
  68.     int         flag;   /*  1:busy, 0:free. */  
  69.     struct task_node    *work;  /*  if exec a work, which work. */  
  70.     struct pthread_node *next;  
  71.     struct pthread_node *prev;  
  72.     pthread_cond_t      cond;   /* when assigned a task, signal this child thread by manager. */  
  73.     pthread_mutex_t     mutex;  
  74. } THREAD_NODE;  
  75.   
  76.   
  77. /* 
  78.  * *the ds of the thread queue 
  79.  */  
  80. //线程队列结构,用于控制空闲线程队列和忙碌线程队列  
  81. typedef struct pthread_queue  
  82. {  
  83.     int         number; /* the number of thread in this queue. */  
  84.     struct pthread_node *head;  
  85.     struct pthread_node *rear;  
  86.     pthread_cond_t      cond;   /* when no idle thread, the manager wait for ,or when a thread return with idle, signal. */  
  87.     pthread_mutex_t     mutex;  
  88. } PTHREAD_QUEUE_T;  
  89.   
  90. //在pthread_poll()中定义的三个结构的指针  
  91. extern PTHREAD_QUEUE_T  *pthread_queue_idle;    /* the idle thread double link queue. */  
  92. extern PTHREAD_QUEUE_T  *pthread_queue_busy;    /* the work thread double link queue. */  
  93. extern TASK_QUEUE_T *task_queue_head;       /* the task queuee single link list. */  
  94.   
  95. void *child_work( void *ptr );  
  96.   
  97. void create_pthread_pool( void );  
  98.   
  99. void init_system( void );  
  100.   
  101. void *thread_manager( void *ptr );  
  102.   
  103. void *prcoess_client( void *ptr );  
  104.   
  105. void *task_manager( void *ptr );  
  106.   
  107. void *monitor( void *ptr );  
  108.   
  109. void sys_clean( void );  
  110.   
  111. #endif  

基础函数

[cpp]  view plain  copy
 print ?
  1. #include "pthread_pool.h"  
  2.   
  3.   
  4. /* 
  5.  * *child_work:the code exec in child thread 
  6.  * *ptr: the ds of thread_node of current thread. 
  7.  * *return :nothing.void * just avoid warning. 
  8.  */  
  9. /* 
  10.     child_work为创建的线程执行的函数 
  11.     主要用来等待线程属性状态的变化,来判断是否有任务要执行 
  12.     并且判断线程的工作状态的变化,来决定加入哪个线程队列(空闲还是忙碌) 
  13. */  
  14. void *  
  15. child_work( void *ptr )  
  16. {  
  17.     //这里的ptr为(void *) &temp[i]  
  18.     THREAD_NODE * self = (THREAD_NODE *) ptr;  
  19.   
  20.     /*modify the tid attribute the first time exec */  
  21.     pthread_mutex_lock( &self->mutex );  
  22.     self->tid = syscall( SYS_gettid );//获得线程自身id  
  23.     pthread_mutex_unlock( &self->mutex );  
  24.   
  25.     while ( 1 )  
  26.     {  
  27.         pthread_mutex_lock( &self->mutex );  
  28.   
  29.         /*if no task exec,blocked */  
  30.         /*  
  31.             关键的一句话 
  32.             从线程的属性struct task_node *work(即为self->work) 
  33.             判断是否已给当前线程分配任务 
  34.         */  
  35.         //如果该线程尚没有分配任务,则通过条件变量阻塞等待条件变量self->cond  
  36.         if ( NULL == self->work )   
  37.         {  
  38.             pthread_cond_wait( &self->cond, &self->mutex );  
  39.         }  
  40.   
  41.         pthread_mutex_lock( &self->work->mutex );  
  42.   
  43.         /*execute the real work.  
  44.             开始执行任务 
  45.         */  
  46.         self->work->fun( self->work->arg );  
  47.   
  48.         /*after finished the work  
  49.             任务执行完后,撤销任务的属性,并销毁任务本身,释放其占用的资源 
  50.         */  
  51.         self->work->fun       = NULL;  
  52.         self->work->flag  = 0;  
  53.         self->work->tid       = 0;  
  54.         self->work->next  = NULL;  
  55.   
  56.         free( self->work->arg );  
  57.   
  58.         pthread_mutex_unlock( &self->work->mutex ); /* unlock the task */  
  59.         pthread_mutex_destroy( &self->work->mutex );  
  60.   
  61.         /*free the task space */  
  62.         free( self->work );  
  63.   
  64.         /*make self thread no work */  
  65.         self->work   = NULL;  
  66.         self->flag   = 0;  
  67.   
  68.   
  69.         /* 
  70.          * *get new task from the task_link if not NULL. 
  71.          * *there no idle thread if there are task to do. 
  72.          * *if on task ,make self idle and add to the idle queue. 
  73.          */  
  74.         /* 
  75.             执行完上一个任务后,查看任务队列中是否还有任务      
  76.         */  
  77.         pthread_mutex_lock( &task_queue_head->mutex );  
  78.         if ( task_queue_head->head != NULL )//如果有任务,则分配任务  
  79.         {  
  80.             TASK_NODE * temp = task_queue_head->head;  
  81.   
  82.             /*get the first task */  
  83.             task_queue_head->head = task_queue_head->head->next;  
  84.   
  85.             /*modify self thread attribute */  
  86.             self->flag   = 1;  
  87.             self->work   = temp;  
  88.             temp->tid    = self->tid;  
  89.             temp->next   = NULL;  
  90.             temp->flag   = 1;  
  91.   
  92.             task_queue_head->number--;  
  93.   
  94.             pthread_mutex_unlock( &task_queue_head->mutex );  
  95.   
  96.             pthread_mutex_unlock( &self->mutex );  
  97.   
  98.             continue;  
  99.         }  
  100.         else //如果没有任务,从忙碌线程队列中删除此线程,将其加入空闲线程队列中    
  101.         {  
  102.             /*no task need to exec, add self to idle queue and del from busy queue */  
  103.             pthread_mutex_unlock( &task_queue_head->mutex );  
  104.   
  105.             pthread_mutex_lock( &pthread_queue_busy->mutex );  
  106.   
  107.             /*self is the last execte thread  
  108.                 如果此线程是忙碌的线程队列中的仅剩的一个线程 
  109.             */  
  110.             if ( pthread_queue_busy->head == self  
  111.                  && pthread_queue_busy->rear == self )  
  112.             {  
  113.                 pthread_queue_busy->head = pthread_queue_busy->rear = NULL;  
  114.                 self->next           = self->prev = NULL;  
  115.             }  
  116.             /*the first one thread in busy queue  
  117.                 如果此线程是忙碌的线程队列中的第一个线程 
  118.             */  
  119.             else if ( pthread_queue_busy->head == self  
  120.                   && pthread_queue_busy->rear != self )  
  121.             {  
  122.                 pthread_queue_busy->head = pthread_queue_busy->head->next;  
  123.                 pthread_queue_busy->head->prev    = NULL;  
  124.   
  125.                 self->next = self->prev = NULL;  
  126.             }  
  127.             /*the last one thread in busy queue  
  128.                 如果此线程是忙碌的线程队列中的末尾的一个线程 
  129.             */  
  130.             else if ( pthread_queue_busy->head != self  
  131.                   && pthread_queue_busy->rear == self )  
  132.             {  
  133.                 pthread_queue_busy->rear = pthread_queue_busy->rear->prev;  
  134.                 pthread_queue_busy->rear->next    = NULL;  
  135.   
  136.                 self->next = self->prev = NULL;  
  137.             }  
  138.             /*middle one  
  139.                 如果此线程是忙碌的线程队列中的中间的某个线程 
  140.             */  
  141.             else{  
  142.                 self->next->prev  = self->prev;  
  143.                 self->prev->next  = self->next;  
  144.                 self->next       = self->prev = NULL;  
  145.             }  
  146.   
  147.             pthread_mutex_unlock( &pthread_queue_busy->mutex );  
  148.   
  149.             /*add self to the idle queue  
  150.                 将此线程加入空闲线程队列中 
  151.             */  
  152.             pthread_mutex_lock( &pthread_queue_idle->mutex );  
  153.   
  154.             /*now the idle queue is empty  
  155.                 判断空闲线程队列的情况,根据不同的情况将此线程加入不同的位置 
  156.             */  
  157.             if ( pthread_queue_idle->head == NULL  
  158.                  || pthread_queue_idle->rear == NULL )  
  159.             {  
  160.                 pthread_queue_idle->head = pthread_queue_idle->rear = self;  
  161.                 self->next           = self->prev = NULL;  
  162.             }else  {  
  163.                 self->next       = pthread_queue_idle->head;  
  164.                 self->prev       = NULL;  
  165.                 self->next->prev  = self;  
  166.   
  167.                 pthread_queue_idle->head = self;  
  168.                 pthread_queue_idle->number++;  
  169.             }  
  170.   
  171.             pthread_mutex_unlock( &pthread_queue_idle->mutex );  
  172.   
  173.             pthread_mutex_unlock( &self->mutex );  
  174.   
  175.             /*signal have idle thread  
  176.                 告知阻塞等待条件变量pthread_queue_idle->cond的位置已有空闲线程 
  177.             */  
  178.             pthread_cond_signal( &pthread_queue_idle->cond );  
  179.         }  
  180.     }  
  181. }  
  182.   
  183.   
  184. /* 
  185.  * *create thread pool when the system on, and thread number is THREAD_DEF_NUM. 
  186.  * *when init, initial all the thread into a double link queue and all wait fo self->cond. 
  187.  */  
  188. void  
  189. create_pthread_pool( void )  
  190. {  
  191.     //分配线程节点  
  192.     THREAD_NODE * temp =  
  193.         (THREAD_NODE *) malloc( sizeof(THREAD_NODE) * THREAD_DEF_NUM );  
  194.   
  195.     if ( temp == NULL )  
  196.     {  
  197.         printf( " malloc failure\n" );  
  198.         exit( EXIT_FAILURE );  
  199.     }  
  200.   
  201.     /*init as a double link queue  
  202.         初始化为双向链式队列 
  203.     */  
  204.     int i;  
  205.   
  206.     //THREAD_DEF_NUM为线程池中线程的最大数量  
  207.     //for循环开始创建线程池  
  208.     for ( i = 0; i < THREAD_DEF_NUM; i++ )  
  209.     {  
  210.         temp[i].tid     = i + 1;  
  211.         temp[i].work    = NULL;  
  212.         temp[i].flag    = 0;  
  213.   
  214.         if ( i == THREAD_DEF_NUM - 1 )  
  215.             temp[i].next = NULL;  
  216.   
  217.         if ( i == 0 )  
  218.             temp[i].prev = NULL;  
  219.   
  220.         //双向链表的体现  
  221.         temp[i].prev    = &temp[i - 1];  
  222.         temp[i].next    = &temp[i + 1];  
  223.   
  224.         pthread_cond_init( &temp[i].cond, NULL );  
  225.         pthread_mutex_init( &temp[i].mutex, NULL );  
  226.   
  227.         /*create this thread  
  228.             在此创建线程,各个线程执行的函数为child_work 
  229.         */  
  230.         pthread_create( &temp[i].tid, NULL, child_work, (void *) &temp[i] );  
  231.     }  
  232.   
  233.     /*modify the idle thread queue attribute  
  234.         修改空闲线程队列的属性 
  235.     */  
  236.     pthread_mutex_lock( &pthread_queue_idle->mutex );  
  237.   
  238.     pthread_queue_idle->number   = THREAD_DEF_NUM;  
  239.     //此句就将刚创建的那些线程给空闲线程队列  
  240.     pthread_queue_idle->head = &temp[0];  
  241.     pthread_queue_idle->rear = &temp[THREAD_DEF_NUM - 1];  
  242.   
  243.     pthread_mutex_unlock( &pthread_queue_idle->mutex );  
  244. }  
  245.   
  246.   
  247. /* 
  248.  * *init_system :init the system glob pointor. 
  249.  */  
  250. void  
  251. init_system( void )  
  252. {  
  253.     /*init the pthread_queue_idle  
  254.         初始化空闲线程队列,采用的是普通的双向链式结构(未循环) 
  255.     */  
  256.     pthread_queue_idle =  
  257.         (PTHREAD_QUEUE_T *) malloc( sizeof(PTHREAD_QUEUE_T) );  
  258.   
  259.     pthread_queue_idle->number   = 0;  
  260.     pthread_queue_idle->head = NULL;  
  261.     pthread_queue_idle->rear = NULL;  
  262.     pthread_mutex_init( &pthread_queue_idle->mutex, NULL );  
  263.     pthread_cond_init( &pthread_queue_idle->cond, NULL );  
  264.   
  265.     /*init the pthread_queue_busy  
  266.         初始化空闲线程队列,采用的是普通的双向链式结构(未循环) 
  267.     */  
  268.     pthread_queue_busy =  
  269.         (PTHREAD_QUEUE_T *) malloc( sizeof(PTHREAD_QUEUE_T) );  
  270.   
  271.     pthread_queue_busy->number   = 0;  
  272.     pthread_queue_busy->head = NULL;  
  273.     pthread_queue_busy->rear = NULL;  
  274.     pthread_mutex_init( &pthread_queue_busy->mutex, NULL );  
  275.     pthread_cond_init( &pthread_queue_busy->cond, NULL );  
  276.   
  277.     /*init the task_queue_head  
  278.         初始化任务队列,采用单向链表 
  279.     */  
  280.     task_queue_head = (TASK_QUEUE_T *) malloc( sizeof(TASK_QUEUE_T) );  
  281.   
  282.     task_queue_head->head    = NULL;  
  283.     task_queue_head->number = 0;  
  284.     pthread_cond_init( &task_queue_head->cond, NULL );  
  285.     pthread_mutex_init( &task_queue_head->mutex, NULL );  
  286.   
  287.     /*create thread poll  
  288.         创建线程池 
  289.     */  
  290.     create_pthread_pool();  
  291. }  
  292.   
  293.   
  294. /* 
  295.  * *thread_manager:code exec in manager thread. 
  296.  *               block on task_queue_head->cond when no task come. 
  297.  *               block on pthread_queue_idle->cond when no idle thread 
  298.  **ptr:no used ,in order to avoid warning. 
  299.  **return :nothing. 
  300.  */  
  301.   
  302. void *  
  303. thread_manager( void *ptr )  
  304. {  
  305.     while ( 1 )  
  306.     {  
  307.         THREAD_NODE * temp_thread   = NULL;  
  308.         TASK_NODE   * temp_task = NULL;  
  309.   
  310.         /* 
  311.          * *get a new task, and modify the task_queue. 
  312.          * *if no task block om task_queue_head->cond. 
  313.          */  
  314.         pthread_mutex_lock( &task_queue_head->mutex );  
  315.         //如果任务队列为空,则阻塞等待条件变量task_queue_head->cond  
  316.         if ( task_queue_head->number == 0 )  
  317.             pthread_cond_wait( &task_queue_head->cond,  
  318.                        &task_queue_head->mutex );  
  319.   
  320.         //如果不为空,则开始准备分配任务,并修改任务队列属性  
  321.         temp_task       = task_queue_head->head;  
  322.         task_queue_head->head    = task_queue_head->head->next;  
  323.         task_queue_head->number--;  
  324.   
  325.         pthread_mutex_unlock( &task_queue_head->mutex );  
  326.   
  327.   
  328.         /* 
  329.          * *get a new idle thread, and modify the idle_queue. 
  330.          * *if no idle thread, block on pthread_queue_idle->cond. 
  331.          */  
  332.         //有了任务之后,开始判断是否有空闲线程  
  333.         pthread_mutex_lock( &pthread_queue_idle->mutex );  
  334.           
  335.         //如果没有空闲线程,则阻塞等待条件变量pthread_queue_idle->cond  
  336.         if ( pthread_queue_idle->number == 0 )  
  337.             pthread_cond_wait( &pthread_queue_idle->cond,  
  338.                        &pthread_queue_idle->mutex );  
  339.                          
  340.         //如果有空闲线程则取出一个空闲线程,然后修改空闲线程队列属性  
  341.         temp_thread = pthread_queue_idle->head;  
  342.   
  343.         /*if this is the last idle thread ,modiry the head and rear pointor */  
  344.         if ( pthread_queue_idle->head == pthread_queue_idle->rear )  
  345.         {  
  346.             pthread_queue_idle->head = NULL;  
  347.             pthread_queue_idle->rear = NULL;  
  348.         }  
  349.         /*if idle thread number>2, get the first one,modify the head pointor  */  
  350.         else{  
  351.             pthread_queue_idle->head = pthread_queue_idle->head->next;  
  352.             pthread_queue_idle->head->prev    = NULL;  
  353.         }  
  354.   
  355.         pthread_queue_idle->number--;//将空闲线程队列数量减一  
  356.   
  357.         pthread_mutex_unlock( &pthread_queue_idle->mutex );  
  358.   
  359.         /*modify the  task attribute.  
  360.             修改取出的线程的线程结构属性和相关的任务结构属性 
  361.         */  
  362.         pthread_mutex_lock( &temp_task->mutex );  
  363.   
  364.         temp_task->tid   = temp_thread->tid;  
  365.         temp_task->next = NULL;  
  366.         temp_task->flag = 1;  
  367.   
  368.         pthread_mutex_unlock( &temp_task->mutex );  
  369.   
  370.         /*modify the idle thread attribute. */  
  371.         pthread_mutex_lock( &temp_thread->mutex );  
  372.   
  373.         temp_thread->flag    = 1;  
  374.         temp_thread->work    = temp_task;  
  375.         temp_thread->next    = NULL;  
  376.         temp_thread->prev    = NULL;  
  377.   
  378.         pthread_mutex_unlock( &temp_thread->mutex );  
  379.   
  380.         /*add the thread assinged task to the busy queue. */  
  381.         //将已分配任务的线程加入忙碌线程队列中  
  382.         pthread_mutex_lock( &pthread_queue_busy->mutex );  
  383.   
  384.         /*if this is the first one in busy queue */  
  385.         if ( pthread_queue_busy->head == NULL )  
  386.         {  
  387.             pthread_queue_busy->head = temp_thread;  
  388.             pthread_queue_busy->rear = temp_thread;  
  389.             temp_thread->prev        = temp_thread->next = NULL;  
  390.         }else  {  
  391.             /*insert in thre front of the queue */  
  392.             pthread_queue_busy->head->prev    = temp_thread;  
  393.             temp_thread->prev        = NULL;  
  394.             temp_thread->next        = pthread_queue_busy->head;  
  395.             pthread_queue_busy->head = temp_thread;  
  396.             pthread_queue_busy->number++;  
  397.         }  
  398.         pthread_mutex_unlock( &pthread_queue_busy->mutex );  
  399.   
  400.         /*signal the child thread to exec the work */  
  401.         //告知阻塞等待条件变量temp_thread->cond的位置,开始执行任务  
  402.         pthread_cond_signal( &temp_thread->cond );  
  403.     }  
  404. }  
  405.   
  406.   
  407. /* 
  408.  * *code to process the new client in every chilld pthead. 
  409.  * *ptr: the fd come from listen thread that can communicate to the client. 
  410.  * *return:nothing. void * only used to avoid waring. 
  411.  */  
  412. //用来处理任务的函数  
  413. void *  
  414. prcoess_client( void *ptr )  
  415. {  
  416.     int net_fd;  
  417.     net_fd = atoi( (char *) ptr );  
  418.   
  419.     socklen_t   len;  
  420.     char        buf[MAXBUF + 1];  
  421.     /*下面是select用到的变量的定义 */  
  422.     fd_set      rfds;  
  423.     struct timeval  tv;  
  424.     int     retval;  
  425.     int     maxfd = -1;  
  426.   
  427.     while ( 1 )  
  428.     {  
  429.         FD_ZERO( &rfds );                                                       /* 初始化rfds为空 */  
  430.         FD_SET( 0, &rfds );                                                     /* 将标准输入的描述符0加入到集合rfds中 */  
  431.         FD_SET( net_fd, &rfds );                                                /* 将net_fd加入到集合rfds中 */  
  432.         maxfd       = net_fd + 1;  
  433.         tv.tv_sec   = 1;                                                    /* 阻塞等待时间为1s */  
  434.         tv.tv_usec  = 0;  
  435.   
  436.         retval = select( maxfd, &rfds, NULL, NULL, &tv );                       /* 多路复用,同时监测描述符0和net_fd */  
  437.         if ( retval == -1 )                                                     /* select函数执行出错 */  
  438.         {  
  439.             perror( "select" );  
  440.             exit( EXIT_FAILURE );  
  441.         }else if ( retval == 0 )                                                /* select函数执行超时 */  
  442.             continue;  
  443.         else/*有描述符引起异常 */  
  444.             if ( FD_ISSET( 0, &rfds ) )                                     /* 判断是不是标准输入0引起的异常 */  

你可能感兴趣的:(linux编程之网络编程)