一個線程池程序的收藏

thread-pool.h

 

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <pthread.h>
#include <signal.h>

#ifndef TPBOOL
typedef int TPBOOL;
#endif

#ifndef TRUE
#define TRUE 1
#endif

#ifndef FALSE
#define FALSE 0
#endif

#define BUSY_THRESHOLD 0.5 //(busy thread)/(all thread threshold)
#define MANAGE_INTERVAL 5 //tp manage thread sleep interval

typedef struct tp_work_s TP_WORK;
typedef struct tp_work_desc_s TP_WORK_DESC;
typedef struct tp_thread_info_s TP_THREAD_INFO;
typedef struct tp_thread_pool_s TP_THREAD_POOL;

//base thread struct
struct tp_work_s{
    //main process function. user interface
    void (*process_job)(TP_WORK *this, TP_WORK_DESC *job);
};

//thread parm
struct tp_work_desc_s{
    char    *pcInNum; //call in
    char    *pcOutNum; //call out
    int      iChnlNum; //channel num
};

//thread info
struct tp_thread_info_s{
    pthread_t       thread_id; //thread id num
    TPBOOL          is_busy; //thread status:true-busy;flase-idle
    pthread_cond_t  thread_cond; 
    pthread_mutex_t thread_lock;
    TP_WORK        *th_work;
    TP_WORK_DESC   *th_job;
};

//main thread pool struct
struct tp_thread_pool_s{
    int             min_th_num;      //min thread number in the pool
    int             cur_th_num;      //current thread number in the pool
    int             max_th_num;         //max thread number in the pool
    pthread_mutex_t tp_lock;
    pthread_t       manage_thread_id;   //manage thread id num
    TP_THREAD_INFO *thread_info;     //work thread relative thread info
   void (*process_job)(TP_THREAD_POOL *this, TP_WORK *worker, TP_WORK_DESC *job);
    TPBOOL (*init)(TP_THREAD_POOL *this);
    void (*close)(TP_THREAD_POOL *this);
 
    int  (*get_thread_by_id)(TP_THREAD_POOL *this, int id);
    TPBOOL (*add_thread)(TP_THREAD_POOL *this);
    TPBOOL (*delete_thread)(TP_THREAD_POOL *this);
    int (*get_tp_status)(TP_THREAD_POOL *this);
};

#ifndef _THREAD_ERR_
#define _THREAD_ERR_

#define OM_ERRMSG_LEN 200
char    acErrMsg[OM_ERRMSG_LEN];    /* 錯誤信息 */

#else

extern char acErrMsg[OM_ERRMSG_LEN];    /* 錯誤信息 */

#endif

TP_THREAD_POOL *creat_thread_pool(int min_num, int max_num);

 

thread-pool.c

 

 

 

#include "thread-pool.h"

static void    *tp_work_thread( void *pthread );
static void    *tp_manage_thread( void *pthread );

static TPBOOL   tp_init( TP_THREAD_POOL *this );
static void     tp_close( TP_THREAD_POOL *this );
static void     tp_process_job( TP_THREAD_POOL *this, TP_WORK *worker, TP_WORK_DESC *job );
static int      tp_get_thread_by_id( TP_THREAD_POOL *this, int id );
static TPBOOL   tp_add_thread( TP_THREAD_POOL *this );
static TPBOOL   tp_delete_thread( TP_THREAD_POOL *this );
static int      tp_get_tp_status( TP_THREAD_POOL *this );

/*
 * user interface. creat thread pool.
 * para:
 *  num: min thread number to be created in the pool
 * return:
 *  thread pool struct instance be created successfully
*/
TP_THREAD_POOL *creat_thread_pool( int min_num, int max_num )
{
 TP_THREAD_POOL *this;
 this = (TP_THREAD_POOL*)malloc(sizeof(TP_THREAD_POOL)); 

 memset( this, 0x00, sizeof(TP_THREAD_POOL) );
 
 //init member function ponter
 this->init = tp_init;
 this->close = tp_close;
 this->process_job = tp_process_job;
 this->get_thread_by_id = tp_get_thread_by_id;
 this->add_thread = tp_add_thread;
 this->delete_thread = tp_delete_thread;
 this->get_tp_status = tp_get_tp_status;

 //init member var
 this->min_th_num = min_num;
 this->cur_th_num = this->min_th_num;
 this->max_th_num = max_num;
 pthread_mutex_init(&this->tp_lock, NULL);

 //malloc mem for num thread info struct
 if(NULL != this->thread_info)
 {
  free(this->thread_info);
 }
 
 this->thread_info = (TP_THREAD_INFO*)malloc(sizeof(TP_THREAD_INFO)*this->max_th_num);

 return this;
}

/*
* member function reality. thread pool init function.
* para:
*  this: thread pool struct instance ponter
* return:
*  true: successful; false: failed
*/
TPBOOL tp_init( TP_THREAD_POOL *this ){
 int i;
 int err;
 
 //creat work thread and init work thread info
 for( i=0; i<this->min_th_num; i++ ){
  pthread_cond_init(&this->thread_info[i].thread_cond, NULL );
  pthread_mutex_init(&this->thread_info[i].thread_lock, NULL );
  
  err = pthread_create(&this->thread_info[i].thread_id, NULL, tp_work_thread, this );
  if(0 != err){
      memset( acErrMsg, 0x00, sizeof(acErrMsg) );
      snprintf( acErrMsg, sizeof(acErrMsg), "tp_init: creat work thread failed/n" );
#if THREAD_DBG
   printf( "tp_init: creat work thread failed/n" );
#endif
   return FALSE;
  }
#if THREAD_DBG
  printf( "tp_init: creat work thread %d/n", this->thread_info[i].thread_id );
#endif
 }

 //creat manage thread
 err = pthread_create( &this->manage_thread_id, NULL, tp_manage_thread, this );
 if(0 != err){
  memset( acErrMsg, 0x00, sizeof(acErrMsg) );
  snprintf( acErrMsg, sizeof(acErrMsg), "tp_init: creat manage thread failed/n" );
#if THREAD_DBG
  printf( "tp_init: creat manage thread failed/n" );
#endif
  return FALSE;
 }
#if THREAD_DBG
 printf( "tp_init: creat manage thread %d/n", this->manage_thread_id );
#endif
 return TRUE;
}

/*
* member function reality. thread pool entirely close function.
* para:
*  this: thread pool struct instance ponter
* return:
*/
void tp_close( TP_THREAD_POOL *this ){
 int i;
 
 //close work thread
 for( i=0; i<this->cur_th_num; i++ ){
  kill( this->thread_info[i].thread_id, SIGKILL );
  pthread_mutex_destroy( &this->thread_info[i].thread_lock );
  pthread_cond_destroy( &this->thread_info[i].thread_cond );
#if THREAD_DBG
  printf( "tp_close: kill work thread %d/n", this->thread_info[i].thread_id );
#endif
 }

 //close manage thread
 kill( this->manage_thread_id, SIGKILL );
 pthread_mutex_destroy( &this->tp_lock );
#if THREAD_DBG
 printf( "tp_close: kill manage thread %d/n", this->manage_thread_id );
#endif
 
 //free thread struct
 free( this->thread_info );
}

/*
* member function reality. main interface opened.
* after getting own worker and job, user may use the function to process the task.
* para:
*  this: thread pool struct instance ponter
* worker: user task reality.
* job: user task para
* return:
*/
void tp_process_job( TP_THREAD_POOL *this, TP_WORK *worker, TP_WORK_DESC *job ){
 int i;
 int tmpid;

 //fill this->thread_info's relative work key
 for(i=0;i<this->cur_th_num;i++){
  pthread_mutex_lock(&this->thread_info[i].thread_lock);
  if(!this->thread_info[i].is_busy){
#if THREAD_DBG
   printf("tp_process_job: %d thread idle, thread id is %d/n", i, this->thread_info[i].thread_id);
#endif
   //thread state be set busy before work
     this->thread_info[i].is_busy = TRUE;
   pthread_mutex_unlock(&this->thread_info[i].thread_lock);
   
   this->thread_info[i].th_work = worker;
   this->thread_info[i].th_job = job;
#if THREAD_DBG
   printf("tp_process_job: informing idle working thread %d, thread id is %d/n", i, this->thread_info[i].thread_id);
#endif
   pthread_cond_signal(&this->thread_info[i].thread_cond);

   return;
  }
  else
   pthread_mutex_unlock(&this->thread_info[i].thread_lock);  
 }//end of for

 //if all current thread are busy, new thread is created here
 pthread_mutex_lock(&this->tp_lock);
 if( this->add_thread(this) ){
  i = this->cur_th_num - 1;
  tmpid = this->thread_info[i].thread_id;
  this->thread_info[i].th_work = worker;
  this->thread_info[i].th_job = job;
 }
 pthread_mutex_unlock(&this->tp_lock);
 
 //send cond to work thread
#if THREAD_DBG
 printf("tp_process_job: informing idle working thread %d, thread id is %d/n", i, this->thread_info[i].thread_id);
#endif
 pthread_cond_signal(&this->thread_info[i].thread_cond);
 return; 
}

/**
  * member function reality. get real thread by thread id num.
  * para:
  *  this: thread pool struct instance ponter
  * id: thread id num
  * return:
  *  seq num in thread info struct array
  */
int tp_get_thread_by_id( TP_THREAD_POOL *this, int id ){
 int i;

 for(i=0;i<this->cur_th_num;i++){
  if(id == this->thread_info[i].thread_id)
   return i;
 }

 return -1;
}

/**
  * member function reality. add new thread into the pool.
  * para:
  *  this: thread pool struct instance ponter
  * return:
  *  true: successful; false: failed
  */
static TPBOOL tp_add_thread( TP_THREAD_POOL *this ){
 int err;
 TP_THREAD_INFO *new_thread;
 
 if( this->max_th_num <= this->cur_th_num )
  return FALSE;
  
 //malloc new thread info struct
 new_thread = &this->thread_info[this->cur_th_num];
 
 //init new thread's cond & mutex
 pthread_cond_init(&new_thread->thread_cond, NULL);
 pthread_mutex_init(&new_thread->thread_lock, NULL);

 //init status is busy
 new_thread->is_busy = TRUE;

 //add current thread number in the pool.
 this->cur_th_num++;
 
 err = pthread_create(&new_thread->thread_id, NULL, tp_work_thread, this);
 if(0 != err){
  memset( acErrMsg, 0x00, sizeof(acErrMsg) );
  snprintf( acErrMsg, sizeof(acErrMsg), "tp_add_thread: creat thread failed/n" );
  free(new_thread);
  return FALSE;
 }
#if THREAD_DBG
 printf("tp_add_thread: creat work thread %d/n", this->thread_info[this->cur_th_num-1].thread_id);
#endif
 
 return TRUE;
}

/**
  * member function reality. delete idle thread in the pool.
  * only delete last idle thread in the pool.
  * para:
  *  this: thread pool struct instance ponter
  * return:
  *  true: successful; false: failed
  */
static TPBOOL tp_delete_thread( TP_THREAD_POOL *this ){
 //current thread num can't < min thread num
 if(this->cur_th_num <= this->min_th_num){
  memset( acErrMsg, 0x00, sizeof(acErrMsg) );
  snprintf( acErrMsg, sizeof(acErrMsg), "tp_delete_thread: current thread num can't < min thread num/n" );
     return FALSE;
 }

 //if last thread is busy, do nothing
 if(this->thread_info[this->cur_th_num-1].is_busy){
  memset( acErrMsg, 0x00, sizeof(acErrMsg) );
  snprintf( acErrMsg, sizeof(acErrMsg), "tp_delete_thread: last thread is busy/n" );
     return FALSE;
 }


 //kill the idle thread and free info struct
 kill(this->thread_info[this->cur_th_num-1].thread_id, SIGKILL);
 pthread_mutex_destroy(&this->thread_info[this->cur_th_num-1].thread_lock);
 pthread_cond_destroy(&this->thread_info[this->cur_th_num-1].thread_cond);

 //after deleting idle thread, current thread num -1
 this->cur_th_num--;

 return TRUE;
}

/**
  * member function reality. get current thread pool status:idle, normal, busy, .etc.
  * para:
  *  this: thread pool struct instance ponter
  * return:
  *  0: idle; 1: normal or busy(don't process)
  */
static int  tp_get_tp_status( TP_THREAD_POOL *this ){
 float busy_num = 0.0;
 int i;

 //get busy thread number
 for(i=0;i<this->cur_th_num;i++){
  if(this->thread_info[i].is_busy)
   busy_num++;
 }

 //0.2? or other num?
 if(busy_num/(this->cur_th_num) < BUSY_THRESHOLD)
  return 0;//idle status
 else
  return 1;//busy or normal status 
}

/**
  * internal interface. real work thread.
  * para:
  *  pthread: thread pool struct ponter
  * return:
  */
static void *tp_work_thread( void *pthread ){
 pthread_t curid;//current thread id
 int nseq;//current thread seq in the this->thread_info array
 TP_THREAD_POOL *this = (TP_THREAD_POOL*)pthread;//main thread pool struct instance

 //get current thread id
 curid = pthread_self();
 
 //get current thread's seq in the thread info struct array.
 nseq = this->get_thread_by_id(this, curid);
 if(nseq < 0)
  return;
 
#if THREAD_DBG
 printf("entering working thread %d, thread id is %d/n", nseq, curid);
#endif

 //wait cond for processing real job.
 while( TRUE ){
  pthread_mutex_lock(&this->thread_info[nseq].thread_lock);
  pthread_cond_wait(&this->thread_info[nseq].thread_cond, &this->thread_info[nseq].thread_lock);
  pthread_mutex_unlock(&this->thread_info[nseq].thread_lock);  
 
#if THREAD_DBG
     printf("%d thread do work!/n", pthread_self());
#endif

  TP_WORK *work = this->thread_info[nseq].th_work;
  TP_WORK_DESC *job = this->thread_info[nseq].th_job;

  //process
  work->process_job(work, job);

  //thread state be set idle after work
  pthread_mutex_lock(&this->thread_info[nseq].thread_lock);  
  this->thread_info[nseq].is_busy = FALSE;
  pthread_mutex_unlock(&this->thread_info[nseq].thread_lock);
  
#if THREAD_DBG
     printf("%d do work over/n", pthread_self());
#endif
 } 
}

/**
  * internal interface. manage thread pool to delete idle thread.
  * para:
  *  pthread: thread pool struct ponter
  * return:
  */
static void *tp_manage_thread(void *pthread){
 TP_THREAD_POOL *this = (TP_THREAD_POOL*)pthread;//main thread pool struct instance

 //1?
 sleep(MANAGE_INTERVAL);

 do{
  if( this->get_tp_status(this) == 0 ){
   do{
    if( !this->delete_thread(this) )
     break;
   }while(TRUE);
  }//end for if

  //1?
  sleep(MANAGE_INTERVAL);
 }while(TRUE);
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章