最简单的线程池

心不动则不痛 提交于 2020-01-12 18:24:24

=================== thread_pool.h ===============================

#ifndef THREAD_POOL_H__
#define THREAD_POOL_H__
  
#include <pthread.h>
  
/* 要执行的任务链表 */
typedef struct tpool_work {
  void*               (*routine)(void*);       /* 任务函数 */
  void                *arg;                    /* 传入任务函数的参数 */
  struct tpool_work   *next;                    
}tpool_work_t;
  
typedef struct tpool {
  int             shutdown;                    /* 线程池是否销毁 */
  int             max_thr_num;                /* 最大线程数 */
  pthread_t       *thr_id;                    /* 线程ID数组 */
  tpool_work_t    *queue_head;                /* 线程链表 */
  pthread_mutex_t queue_lock;                    
  pthread_cond_t  queue_ready;    
}tpool_t;
  
/*
* @brief     创建线程池 
* @param     max_thr_num 最大线程数
* @return     0: 成功 其他: 失败  
*/
int
tpool_create(int max_thr_num);
  
/*
* @brief     销毁线程池 
*/
void
tpool_destroy();
  
/*
@brief     向线程池中添加任务
@param    routine 任务函数指针
@param     arg 任务函数参数
@return     0: 成功 其他:失败 
*/
int
tpool_add_work(void*(*routine)(void*), void *arg);
 
#endif

----------------------------------------------------------------------thread_pool.h-----------------------------------------

========================thread_pool.c ==================================

#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <stdio.h>
 
#include "thread_pool.h"
 
static tpool_t *tpool = NULL;
  
 /* 工作者线程函数, 从任务链表中取出任务并执行 */
 static void* 
 thread_routine(void *arg)
 {
     tpool_work_t *work;
    
     while(1) {
         /* 如果线程池没有被销毁且没有任务要执行,则等待 */
         pthread_mutex_lock(&tpool->queue_lock);
         while(!tpool->queue_head && !tpool->shutdown) {///线程池没有被销毁,且没有任务要执行
             pthread_cond_wait(&tpool->queue_ready, &tpool->queue_lock);
         }
         if (tpool->shutdown) {///线程池被销毁
             pthread_mutex_unlock(&tpool->queue_lock);
             pthread_exit(NULL);
         }
         work = tpool->queue_head;
         tpool->queue_head = tpool->queue_head->next;///获得任务后线程池偏移。
         pthread_mutex_unlock(&tpool->queue_lock);
  
         work->routine(work->arg);
         free(work);
      }
      
     return NULL;   
 }
  
 /*
  * 创建线程池 
  */
 int
 tpool_create(int max_thr_num)
  {
      int i;
   
      tpool = calloc(1, sizeof(tpool_t));
      if (!tpool) {
          printf("%s: calloc failed\n", __FUNCTION__);
          exit(1);
      }
     
     /* 初始化 */
     tpool->max_thr_num = max_thr_num;
     tpool->shutdown = 0;///0代表未被销毁
     tpool->queue_head = NULL;
     if (pthread_mutex_init(&tpool->queue_lock, NULL) !=0) {///初始化互斥量
         printf("%s: pthread_mutex_init failed, errno:%d, error:%s\n",
             __FUNCTION__, errno, strerror(errno));
         exit(1);
     }
     if (pthread_cond_init(&tpool->queue_ready, NULL) !=0 ) {///初始化条件变量
         printf("%s: pthread_cond_init failed, errno:%d, error:%s\n", 
             __FUNCTION__, errno, strerror(errno));
         exit(1);
     }
     
     /* 创建工作者线程 */
     tpool->thr_id = calloc(max_thr_num, sizeof(pthread_t));
     if (!tpool->thr_id) {
         printf("%s: calloc failed\n", __FUNCTION__);
         exit(1);
     }
     ///创建线程池
     for (i = 0; i < max_thr_num; ++i) {
         if (pthread_create(&tpool->thr_id[i], NULL, thread_routine, NULL) != 0){
             printf("%s:pthread_create failed, errno:%d, error:%s\n", __FUNCTION__, 
                 errno, strerror(errno));
             exit(1);
         }
         /*
         优先级 []大于->大于&
         第一个参数为指向线程标识符的指针。
         第二个参数用来设置线程属性。
         第三个参数是线程运行函数的起始地址。
         最后一个参数是运行函数的参数。
         */
         
         
     }    
  
     return 0;
 }
  
 /* 销毁线程池 */
 void
 tpool_destroy()
 {
     int i;
     tpool_work_t *member;
  
     if (tpool->shutdown) {///线程池已经被销毁则直接返回。
         return;
     }
     tpool->shutdown = 1;///代表线程池被设置为销毁。
  
     /* 通知所有正在等待的线程 */
     pthread_mutex_lock(&tpool->queue_lock);
     pthread_cond_broadcast(&tpool->queue_ready);///
     pthread_mutex_unlock(&tpool->queue_lock);
     for (i = 0; i < tpool->max_thr_num; ++i) {
         pthread_join(tpool->thr_id[i], NULL);///回收退出的线程
     }
     free(tpool->thr_id);
  
     while(tpool->queue_head) {
         member = tpool->queue_head;
         tpool->queue_head = tpool->queue_head->next;
         free(member);
     }
  
     pthread_mutex_destroy(&tpool->queue_lock);    
     pthread_cond_destroy(&tpool->queue_ready);
  
     free(tpool);    
 }
  
 /* 向线程池添加任务 */
 int
 tpool_add_work(void*(*routine)(void*), void *arg)
 {
     tpool_work_t *work, *member;
     
     if (!routine){
         printf("%s:Invalid argument\n", __FUNCTION__);
         return -1;
     }
     
     work = malloc(sizeof(tpool_work_t));
     if (!work) {
         printf("%s:malloc failed\n", __FUNCTION__);
         return -1;
     }
     work->routine = routine;
     work->arg = arg;
     work->next = NULL;
  
     pthread_mutex_lock(&tpool->queue_lock);    
     member = tpool->queue_head;
     if (!member) {///当前任务队列为空,添加的为第一个任务
         tpool->queue_head = work;
     } else {///将任务添加到队列的末尾
         while(member->next) {
             member = member->next;
         }
         member->next = work;
     }
     /* 通知工作者线程,有新任务添加 */
     pthread_cond_signal(&tpool->queue_ready);///应该是随机通知一个等待线程
     pthread_mutex_unlock(&tpool->queue_lock);
 
return 0;    
}

--------------------------------------------------thread_pool.c-----------------------------------------

 

=====================test.c=====================

/*
 创建线程池后,线程池while(1)等待任务,tpool_add_work添加任务。
*/
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include "thread_pool.h"
  
 void *func(void *arg)
 {
     printf("thread %d\n", *((int *)arg));
     return NULL;
 }
  
 int
 main(int arg, char **argv)
 {
     if (tpool_create(5) != 0) {
         printf("tpool_create failed\n");
         exit(1);
     }
     
     int i;
     int i_num[10]={0};///使用数组不使用变量的原因是,传入线程后,值可能会变化。
     /*
     例如如果使用变量 i_num = 0;
     for (i = 0; i < 10; ++i) {///添加10个任务到线程池
         tpool_add_work(func, (void*)(&i_num));
     }
     则可能传入的i_num的值不是期望的。
      */
     for(i=0;i<10;++i)
     {
        i_num[i]=i;
     }
     for (i = 0; i < 10; ++i) {///添加10个任务到线程池
         tpool_add_work(func, (void*)(&(i_num[i])));
     }
     sleep(2);
     tpool_destroy();
     return 0;
 }

----------------test.c---------------------

运行结果如下图所示:

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!