web服务器开发之简单的线程池实现

线程池就是把多个进程放在一个假想容器里统一管理。内部由任务队列,一堆线程,管理者线程组成.

(1)线程管理器:对应一个线程,该线程就是充当一个管理者身份,其能够创建并管理线程池。对线程进行添加,修改,删除

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

(3)任务队列:用来存放没有处理的任务,提供一种缓冲机制,实现这种结构有好几种方法,常用的是队列,主要运用先进先出原理

来看具体的实现

1.管理者线程

管理者线程主要能进行的工作如下,首先是能够创建进程,当实际任务数量大于最小正在等待的任务数量,存活线程数小于最大线程数时,管理者线程需增添线程

if (queue_size >= MIN_WAIT_TASK_NUM && live_thr_num <= pool->max_thr_num) {
            printf("admin add-----------\n");
            pthread_mutex_lock(&(pool->lock));  //在对线程池操作时需先加读写锁
            int add = 0;

            /*一次增加 DEFAULT_THREAD_NUM 个线程*/
            for (i = 0; i < pool->max_thr_num && add < DEFAULT_THREAD_NUM
                        && pool->live_thr_num < pool->max_thr_num; i++) {
                if (pool->threads[i] == 0 || !is_thread_alive(pool->threads[i])) {
                    pthread_create(&(pool->threads[i]), NULL, threadpool_thread, (void *) pool);    //创建线程
                    add++;
                    pool->live_thr_num++;   //更改池中线程数
                    
                }
            }
            pthread_mutex_unlock(&(pool->lock));
        }

当忙线程明显小于存活线程,并且存活的大于最小线程数,管理者线程就需销毁线程

 if ((busy_thr_num * 2) < live_thr_num && live_thr_num > pool->min_thr_num) {
            /*一次销毁DEFAULT_THREAD_NUM个线程*/
            pthread_mutex_lock(&(pool->lock));
            pool->wait_exit_thr_num = DEFAULT_THREAD_NUM;
            pthread_mutex_unlock(&(pool->lock));

            for (i = 0; i < DEFAULT_THREAD_NUM; i++) {
                //通知正在处于空闲的线程,自杀
                pthread_cond_signal(&(pool->queue_not_empty));
                printf("admin cler --\n");
            }
        }

其中还需要设定管理事件间隔,存储当前池中存活的线程数等数据

pthread_mutex_t lock;                 /* 锁住整个结构体 */
   pthread_mutex_t thread_counter;       /* 用于使用忙线程数时的锁 */
   pthread_cond_t  queue_not_full;       /* 条件变量,任务队列不为满 */
   pthread_cond_t  queue_not_empty;      /* 任务队列不为空 */

   pthread_t *threads;                   /* 存放线程的tid,实际上就是管理了线 数组 */
   pthread_t admin_tid;                  /* 管理者线程tid */
   threadpool_task_t *task_queue;        /* 任务队列 */

   /*线程池信息*/
   int min_thr_num;                      /* 线程池中最小线程数 */
   int max_thr_num;                      /* 线程池中最大线程数 */
   int live_thr_num;                     /* 线程池中存活的线程数 */
   int busy_thr_num;                     /* 忙线程,正在工作的线程 */
   int wait_exit_thr_num;                /* 需要销毁的线程数 */

   /*任务队列信息*/
   int queue_front;                      /* 队头 */
   int queue_rear;                       /* 队尾 */
   int queue_size; 
 
   /* 存在的任务数 */
   int queue_max_size;                   /* 队列能容纳的最大任务数 */

   /*状态*/
   int shutdown;                         /* true为关闭 */

 

2.工作线程

对于每个线程没有工作时,处于阻塞状态,有自杀功能,可以取出任务并执行相应的任务

/*工作线程*/
void *
threadpool_thread(void *threadpool)
{
  threadpool_t *pool = (threadpool_t *)threadpool;
  threadpool_task_t task;

  while (true)
  {
    pthread_mutex_lock(&(pool->lock));

    //无任务则阻塞在 任务队列不为空 上,有任务则跳出
    while ((pool->queue_size == 0) && (!pool->shutdown))
    { 
       printf("thread 0x%x is waiting \n", (unsigned int)pthread_self());
       pthread_cond_wait(&(pool->queue_not_empty), &(pool->lock));

       //判断是否需要清除线程,自杀功能
       if (pool->wait_exit_thr_num > 0)
       {
          pool->wait_exit_thr_num--;
          //判断线程池中的线程数是否大于最小线程数,是则结束当前线程
	  if (pool->live_thr_num > pool->min_thr_num)
	  {
	    printf("thread 0x%x is exiting \n", (unsigned int)pthread_self());
	    pool->live_thr_num--;
	    pthread_mutex_unlock(&(pool->lock));
	    pthread_exit(NULL);//结束线程
	  }
       }
    }

    //线程池开关状态
    if (pool->shutdown) //关闭线程池
    {
       pthread_mutex_unlock(&(pool->lock));
       printf("thread 0x%x is exiting \n", (unsigned int)pthread_self());
       pthread_exit(NULL); //线程自己结束自己
    }

    //否则该线程可以拿出任务
    task.function = pool->task_queue[pool->queue_front].function; //出队操作
    task.arg = pool->task_queue[pool->queue_front].arg;

    pool->queue_front = (pool->queue_front + 1) % pool->queue_max_size;  //环型结构
    pool->queue_size--;

    //通知可以添加新任务
    pthread_cond_broadcast(&(pool->queue_not_full));
    
    //释放线程锁
    pthread_mutex_unlock(&(pool->lock));
    
    //执行刚才取出的任务
    printf("thread 0x%x start working \n", (unsigned int)pthread_self());
    pthread_mutex_lock(&(pool->thread_counter));            //锁住忙线程变量
    pool->busy_thr_num++;
    pthread_mutex_unlock(&(pool->thread_counter));

    (*(task.function))(task.arg);                           //执行任务

    //任务结束处理
    printf("thread 0x%x end working \n", (unsigned int)pthread_self());
    pthread_mutex_lock(&(pool->thread_counter));
    pool->busy_thr_num--;
    pthread_mutex_unlock(&(pool->thread_counter));
  }

  pthread_exit(NULL);
}

3.任务队列

主程序可以向其中添加任务,添加后需唤醒线程池中的进程

int 
threadpool_add_task(threadpool_t *pool, void *(*function)(void *arg), void *arg)
{
   pthread_mutex_lock(&(pool->lock));

   /*如果队列满了,调用wait阻塞*/
   while ((pool->queue_size == pool->queue_max_size) && (!pool->shutdown))
   {
      pthread_cond_wait(&(pool->queue_not_full), &(pool->lock));
   }
   /*如果线程池处于关闭状态*/
   if (pool->shutdown)
   {
      pthread_mutex_unlock(&(pool->lock));
      return -1;
   }

   /*清空工作线程的回调函数的参数arg*/
   if (pool->task_queue[pool->queue_rear].arg != NULL)
   {
      free(pool->task_queue[pool->queue_rear].arg);
      pool->task_queue[pool->queue_rear].arg = NULL;
   }
   
   /*添加任务到任务队列*/
   pool->task_queue[pool->queue_rear].function = function;
   pool->task_queue[pool->queue_rear].arg = arg;
   pool->queue_rear = (pool->queue_rear + 1) % pool->queue_max_size;  /* 逻辑环  */
   pool->queue_size++;

   /*添加完任务后,队列就不为空了,唤醒线程池中的一个线程*/
   pthread_cond_signal(&(pool->queue_not_empty));
   pthread_mutex_unlock(&(pool->lock));

   return 0;
}

 

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值