Linux C 实现线程池

最近做的一些工作需要用到线程池技术,因此参考了一些资料和书籍,如《0bug c/c++商用工程之道》。

为此在linux平台上用纯c写了一个线程池的实现。

 

在此列出了原代码。

 

主要用到的数据结构有

1.struct  thread_pool_t    // thread pool 的实现代码

2.struct thread_pool_token_t    //在thread pool 中用到的结构,一个该类型变量代表一条线程

3.struct thread_pool_job_t     //当线前程处理该任务将回调结构

 

设计思路:

主线程创建线程池的控制线程,

管理线程将进入循环来做以下事情:

1.如果当前空闲进程不足并且总线程数没有达到上限,将创建一条空闲线程,至道空闲线程达到3条(见THREAD_POOL_MIN_IDLE_SIZE)

2.不断检查工作任务队列,有则安排一条空闲线程对该任务进行处理

 

普通线程被管理线程创建后也将进入循环来做以下事情:

1.检查当前assign的thread_pool_token_t结构的状态,如果是TREAD_POOL_STATE_BUSY则调用thread_pool_token_t所注册的回调函数来处理任务。

2.完成该任务后检测当前空闲进程够不够,如果太多则退出本线程,否则会改写运行状态为TREAD_POOL_STATE_IDLE后继续循环

 

注册任务:

1.当没有空闲线程可用时将把该任务加入工作任务队列(需定义_THREAD_POOL_JOB_LIST_),以备将来有空闲线程是能够进行处理。

 

 

主要文件 :

1.thread_pool.h

 
#ifndef _LIB_DOL_THREAD_POOL_H_
#define _LIB_DOL_THREAD_POOL_H_

#include "thread_pool.def"

#include <pthread.h>

#define THREAD_POOL_MIN_SIZE      5     /* at least 5 threads, 4 job + 1 manage thread */
#define THREAD_POOL_MIN_IDLE_SIZE 3     /* at least 3 threads idle to improve the efficiency */
#define THREAD_POOL_DEFAULT_SIZE  10    /* default threads in thread pool */
#define THREAD_POOL_MAX_SIZE      100   /* max threads in thread pool */

#define TREAD_POOL_STATE_NOTRUN   0
#define TREAD_POOL_STATE_IDLE     1
#define TREAD_POOL_STATE_BUSY     2

#define TREAD_POOL_REG_OK         0
#define TREAD_POOL_REG_ERR        -1
#define TREAD_POOL_REG_ERR_FULL   -2

#define ETPNOUSE      -2   /* thread pool can not use */
#define ETPERR        -1   /* thread pool over flow */
#define ETPOK          0   /* thread pool register ok */

#define CREATE_THREAD_SLEEP   ( 200 * 1000 //200ms
#define LOOP_SLEEP            ( 150 * 1000 //150ms

typedef void (*job_call_back_t)(void * );

typedef struct _thread_pool_job{
   /* call back function which the thread will call to process this job */
   job_call_back_t call_back;

   /* parameter for call back function */
   void * param;

   /* job desc */
   char desc[64];

#ifdef _THREAD_POOL_JOB_LIST_
   /* if too many job then we will use this list to store the other job */
   struct _thread_pool_job* next;
#endif
}thread_pool_job_t;

struct _thread_pool;

typedef struct _thread_pool_token{
   int                  token_id;
   int                  state;
   int                  total_job; /* total jobs */
   pthread_t            thread_id;
   thread_pool_job_t*  job;
   struct _thread_pool* pool;
   pthread_mutex_t      lock;
} thread_pool_token_t;

typedef struct _thread_pool{
   int  size;         /* thread pool size */
   int  active;       /* total create thread count */
   int  busy;         /* total busy thread count */
   int  idle;         /* total idle thread count */
   int  quit;         /* should we quit the thread 1-quit, 0-loop */
   int  total_job;   /* total process register job */
   int  reg_err;      /* total register err */

#ifdef _THREAD_POOL_JOB_LIST_
   /* use a link list to buff job if too many jobs are registered */
   thread_pool_job_t* job_head;
   /* lock for manuplate job list */
   pthread_mutex_t     job_lock;
#endif

   /* lock */
   pthread_mutex_t     pool_lock;

   /* thread pool core data */
   thread_pool_token_t token[THREAD_POOL_MAX_SIZE];
}thread_pool_t;

/*
* init a thread pool with pool_size threads
* if pool_size is 0 or less than THREAD_POOL_IDLE_SIZE then pool_size set to THREAD_POOL_DEFAULT_SIZE
* if pool_size is larger than THREAD_POOL_MAX_SIZE then pool_size set to THREAD_POOL_MAX_SIZE
* return 0 if ok, -1 if error
*/
int thread_pool_init(thread_pool_t * pool, int pool_size);

/*
* thread pool destroy
*/
void thread_pool_destroy(thread_pool_t * pool);

/*
* pool      -   the thread pool
* call_back -   call back function for thread token to call
* param     -   call back function parameter
* desc      -   tsk description
* it's thread safe when multi thread register thread pool job
*/
int thread_pool_register_job(thread_pool_t * pool, job_call_back_t call_back, void * param, char* desc);

/*
* out put the pool statistic data to stdout
*/
void thread_pool_statistic(thread_pool_t * pool);

/*
* out put the pool run time data to stdout
*/
void thread_pool_runtime(thread_pool_t * pool);

/*
* change the default log file to log_file
*/
void thread_pool_set_log(char* log_file);

/* thread pool token thread serve function */
static void * thread_pool_serve(void * arg);

/* thread pool control thread function */
static void * thread_pool_manage(void * arg);

/* destroy the mutex lock */
static void thread_pool_clean_up_lock(thread_pool_t * pool);

/* thread pool log */
static void thread_pool_log(char* fmt, ...);

/*
*  find a not use token
*  -1 if not found , else the token index
*/
static int thread_pool_find_free_token(thread_pool_t * pool);

/*
*  find a runing and idle token
*  -1 if not found , else the token index
*/
static int thread_pool_find_serve_token(thread_pool_t * pool);

#ifdef _DEBUG_VERSION_
   #define _DOL_FPRINTF_ fprintf
#else
   #define _DOL_FPRINTF_ //fprintf
#endif

#ifdef _THREAD_POOL_JOB_LIST_
/* pop a job from job list */
static thread_pool_job_t* pop_job(thread_pool_t * pool);

/* push a job in job list */
static void push_job(thread_pool_t * pool, thread_pool_job_t* job);

/* destroy the job list */
static void destroy_job_list(thread_pool_job_t* job_head);
#endif

#endif // end if define _LIB_DOL_THREAD_POOL_H_

 2. thread_pool.c

 


//COPYRIGHT AND PERMISSION NOTICE
 
//Copyright (c) 2010, Dolphin Cheung, <[email protected]>.
 
//All rights reserved.
 
//Permission to use, copy, modify, and distribute this software for any purpose
//with or without fee is hereby granted, provided that the above copyright
//notice and this permission notice appear in all copies.
 
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. IN
//NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
//DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
//OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
//OR OTHER DEALINGS IN THE SOFTWARE.
 
//Except as contained in this notice, the name of a copyright holder shall not
//be used in advertising or otherwise to promote the sale, use or other dealings
//in this Software without prior written authorization of the copyright holder.


#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <errno.h>
#include <time.h>
#include <stdarg.h>
#include <string.h>

#include "thread_pool.h"

static const char * default_log_file = "/var/log/libdol_tp.log";
static char real_log_file[256];

/* thread pool token thread serve function */
static void * thread_pool_serve(void * arg){
   thread_pool_token_t* token = (thread_pool_token_t*) arg;
   int self_quit = 0;

   token->state = TREAD_POOL_STATE_IDLE;

   pthread_mutex_lock(&(token->pool->pool_lock));
   token->pool->idle ++;
   token->pool->active++;
   pthread_mutex_unlock(&(token->pool->pool_lock));

   usleep(LOOP_SLEEP);

   thread_pool_log("serve thread create: token:%d thread:%u pid:%d ppid:%d",token->token_id, token->thread_id,(int)getpid(),(int)getppid());

   while(! token->pool->quit){
      /* do we have job ? */
      if(token->state == TREAD_POOL_STATE_BUSY
         && token->job && token->job->call_back){

         /* modify pool stat. */
         pthread_mutex_lock(&(token->pool->pool_lock));
         token->pool->idle --;
         token->pool->busy ++;
         token->pool->total_job ++;
         pthread_mutex_unlock(&(token->pool->pool_lock));

         /*
 * process this job; this job may be a daemon process
 * so it may process all the time, you should design carefully
 * when it's time to quit in the while loop for the daemon process
 * the thread pool have no way to tell the daemon process we will quit
 * so when quit the thread pool, you also need to tell your 
 * daemon process to quit.
 */
         token->job->call_back(token->job->param);

         pthread_mutex_lock(&(token->lock));
         token->total_job ++;
         free(token->job);
         token->job = NULL;
         token->state = TREAD_POOL_STATE_IDLE;
         pthread_mutex_unlock(&(token->lock));
         
         /* modify pool stat. */
         pthread_mutex_lock(&(token->pool->pool_lock));
         token->pool->idle ++;
         token->pool->busy --;

         /* too many idle thread ? */
         if(token->pool->idle > THREAD_POOL_MIN_IDLE_SIZE){
            self_quit = 1;
         }
         pthread_mutex_unlock(&(token->pool->pool_lock));

      }

      if(self_quit){
         break;
      }

      usleep(LOOP_SLEEP);
   }

   thread_pool_log("serve thread quit: token:%d thread:%u job:%d pid:%d ppid:%d",
      token->token_id, token->thread_id,token->total_job,(int)getpid(),(int)getppid());
   //thread quit
   pthread_mutex_lock(&(token->lock));
   token->state = TREAD_POOL_STATE_NOTRUN;
   token->thread_id = 0;
   pthread_mutex_unlock(&(token->lock));

   pthread_mutex_lock(&(token->pool->pool_lock));
   token->pool->idle --;
   token->pool->active --;
   pthread_mutex_unlock(&(token->pool->pool_lock));
   return NULL;
}

/* thread pool control thread function */
static void * thread_pool_manage(void * arg){
   thread_pool_t *pool = (thread_pool_t*) arg;
   thread_pool_job_t* job_node;
   int i, rc , idle, active,busy;

   if(pool == NULL){
      thread_pool_log("WARNING: thread_pool_manage stop when pool is NULL");
      return NULL;
   }

   pool->active++;

   usleep(CREATE_THREAD_SLEEP );
   thread_pool_log("manage thread create. pid:%d ppid:%d",(int)getpid(),(int)getppid());

   while(! pool->quit){
      pthread_mutex_lock(&(pool->pool_lock));
      idle = pool->idle;
      active = pool->active;
      busy = pool->busy;
      pthread_mutex_unlock(&(pool->pool_lock));

      if( idle < THREAD_POOL_MIN_IDLE_SIZE){
         //less than preset idle thread then create new therad
         if(active < pool->size){
            //ok we can create new thread now
            i = thread_pool_find_free_token(pool);
            if(i == -1){
               //sorry , it's unusual case
               _DOL_FPRINTF_(stderr,"WARNING: can not found free token/n");
               thread_pool_log("WARNING: can not found free token when create new thread");
            }else{
               rc = pthread_create(&(pool->token[i].thread_id), NULL, &thread_pool_serve, &(pool->token[i]));
               if(rc !=0 ){
                  fprintf(stderr,"ERROR: thread pool create serve thread fail! code[%d] desc[%s]/n",errno,strerror(errno));
                  thread_pool_log("ERROR: thread pool create serve thread fail! code[%d] desc[%s]/n",errno,strerror(errno));
                  pthread_mutex_lock(&(pool->token[i].lock));
                  pool->token[i].state = TREAD_POOL_STATE_NOTRUN;
                  pthread_mutex_unlock(&(pool->token[i].lock));
               }
               usleep(CREATE_THREAD_SLEEP );
            }
         }else{
            //sorry we're too busy
            _DOL_FPRINTF_(stdout,"WARNING: no more idle thread, total:%d idle:%d busy:%d nrun:%d/n",active,idle,busy,active-idle-busy-1);
            thread_pool_log("WARNING: we're busy, total:%d idle:%d busy:%d nrun:%d",active,idle,busy,active-idle-busy-1);
         }
      }

#ifdef _THREAD_POOL_JOB_LIST_
      while(job_node = pop_job(pool)){
         i = thread_pool_find_serve_token(pool);
         if(i == -1){
            /* we will break the loop if no more serve token found and push back the job */
            push_job(pool,job_node);
            break;
         }else{
            pthread_mutex_lock(&(pool->token[i].lock));
            /* make the register thread safe */
            if(pool->token[i].state == TREAD_POOL_STATE_IDLE){
               pool->token[i].job = job_node;
               /* set thread state to busy and the thread will process the job */
               pool->token[i].state = TREAD_POOL_STATE_BUSY;
            }else{
               push_job(pool,job_node);
            }
            pthread_mutex_unlock(&(pool->token[i].lock));
         }
      }
#endif

      usleep(LOOP_SLEEP );
   }

   /* wait for other serve thread to terminal */
   while(pool->active > 1){
      usleep(LOOP_SLEEP );
   }

   thread_pool_clean_up_lock(pool);
	
   thread_pool_log("thread pool manage thread terminal! pid:%d ppid:%d",(int)getpid(),(int)getppid());
   pool->active --;

   return NULL;
}

void thread_pool_set_log(char* log_file){
   if(log_file == NULL)
      return;
   if(strlen(log_file) > sizeof(real_log_file))
      return;
   strcpy(real_log_file,log_file);
}

/* thread pool log */
static void thread_pool_log(char* fmt, ...){
   va_list args;

   FILE * fo;
   char date[32], ttime[32], filename[128], fpath[128];
   char buffer[1024];
   time_t tnow;
   struct tm * tm_time;

   time(&tnow);
   tm_time = localtime(&tnow);
   strftime(date, sizeof(date), "%y%m%d", tm_time);

   strftime(ttime, sizeof(ttime), "%H%M%S", tm_time);

   sprintf(filename, "%s", real_log_file);

   //if(access(filename, F_OK) != 0){
      //mkdir(fpath, 00777);
      //chmod(fpath, 00777);
   //}
   //chmod(filename, 00666);

   if((fo = fopen(filename, "a")) == 0){
      fprintf(stderr,"cannot open %s", fo);
      return;
   }

   va_start(args,fmt);
   vsprintf(buffer,fmt,args);
   fprintf(fo,"%s %s/n",ttime,buffer);
   va_end(args);

   fclose(fo);
}

int thread_pool_init(thread_pool_t * pool, int pool_size){
   int rc,i;
   pthread_t tid;
   if(pool == NULL){
      return ETPNOUSE;
   }

   memset(pool,0x00,sizeof(thread_pool_t));
   memset(real_log_file,0x00,sizeof(real_log_file));
   sprintf(real_log_file,"%s",default_log_file);

   /* at least */
   if(pool_size < THREAD_POOL_MIN_SIZE)
      pool_size = THREAD_POOL_DEFAULT_SIZE;
   else if(pool_size >= THREAD_POOL_MAX_SIZE )
      pool_size = THREAD_POOL_MAX_SIZE;

   pool->size = pool_size;
   thread_pool_log("thread pool init with size:%d",pool->size);
	
   pthread_mutex_init(&(pool->pool_lock),NULL);
#ifdef _THREAD_POOL_JOB_LIST_
   pthread_mutex_init(&(pool->job_lock),NULL);
   pool->job_head = NULL;
#endif

   for(i=0;i<pool_size;i++){
      pthread_mutex_init(&(pool->token[i].lock),NULL);
      pool->token[i].token_id = i;
      pool->token[i].state = TREAD_POOL_STATE_NOTRUN;
      pool->token[i].job = NULL;
      pool->token[i].pool = pool;
   }

   /* only create the manager thread, and it will create other serve threads */
   rc = pthread_create(&tid, NULL, &thread_pool_manage, pool);
   if(rc !=0 ){
      fprintf(stderr,"ERROR:thread pool create fail! code[%d] desc[%s]/n",errno,strerror(errno));
      thread_pool_log("ERROR:thread pool create fail! code[%d] desc[%s]/n",errno,strerror(errno));
      pthread_mutex_destroy(&(pool->pool_lock));
#ifdef _THREAD_POOL_JOB_LIST_
      pthread_mutex_destroy(&(pool->job_lock));
#endif
      for(i=0;i<pool_size;i++){
         pthread_mutex_destroy(&(pool->token[i].lock));;
      }
      return ETPERR;
   }else{
      _DOL_FPRINTF_(stdout,"thread pool create manage thread %u completed/n",tid);
   }

   usleep(CREATE_THREAD_SLEEP);

   return ETPOK;
}

void thread_pool_destroy(thread_pool_t * pool){
   if(pool == NULL)
      return;

   pool->quit = 1;
   while(pool->active){
      usleep(LOOP_SLEEP );
      _DOL_FPRINTF_(stdout,"Still have %d threads in thread pool/n",pool->active);
   }

#ifdef _THREAD_POOL_JOB_LIST_
   destroy_job_list(pool->job_head);
#endif

   thread_pool_log("thread pool destroy! terminal %d threads; total %d jobs",pool->size, pool->total_job);
}

int thread_pool_register_job(thread_pool_t * pool, job_call_back_t call_back, void * param, char* desc ){
   int i=0,rc;
   thread_pool_job_t* job = (thread_pool_job_t*)malloc(sizeof(thread_pool_job_t));
   if(job == NULL){
      /* no more memory */
      return TREAD_POOL_REG_ERR;
   }

   memset(job,0x00,sizeof(thread_pool_job_t));
   job->call_back = call_back;
   job->param = param;

   if(desc)
      sprintf(job->desc,"%s",desc);
   else
      sprintf(job->desc,"N/A");

   i = thread_pool_find_serve_token(pool);
   if(i == -1){
#ifdef _THREAD_POOL_JOB_LIST_
      job->next = NULL;
      push_job(pool,job);
      return TREAD_POOL_REG_OK;
#else
      if(job)
         free(job);
      pool->reg_err ++;
      return TREAD_POOL_REG_ERR_FULL;
#endif
   }

   pthread_mutex_lock(&(pool->token[i].lock));
   /* make the register thread safe */
   if(pool->token[i].state == TREAD_POOL_STATE_IDLE){
      pool->token[i].job = job;
      /* set thread state to busy and the thread will process the job */
      pool->token[i].state = TREAD_POOL_STATE_BUSY;
      rc = TREAD_POOL_REG_OK;
   }else{
      pool->reg_err ++;
      rc = TREAD_POOL_REG_ERR;
   }
   pthread_mutex_unlock(&(pool->token[i].lock));

   return rc;
}

static void thread_pool_clean_up_lock(thread_pool_t * pool){
   int i;
   if(pool == NULL)
      return;
   for(i=0; i<pool->size; i++){
      pthread_mutex_destroy(&(pool->token[i].lock));
   }

   pthread_mutex_destroy(&(pool->pool_lock));
#ifdef _THREAD_POOL_JOB_LIST_
   pthread_mutex_destroy(&(pool->job_lock));
#endif
}

void thread_pool_statistic(thread_pool_t * pool){
   if(pool == NULL){
      _DOL_FPRINTF_(stderr,"thread_pool_statistic(NULL)/n");
      return;
   }

   fprintf(stdout,"/n *** thread pool statistic ***/n");
   fprintf(stdout," size:%d/t job:%d/t reg_err:%d/n active:%d/t busy:%d/t idle:%d/t/n"
          ,pool->size,pool->total_job,pool->reg_err,pool->active,pool->busy,pool->idle);
}

void thread_pool_runtime(thread_pool_t * pool){
   int i;
   thread_pool_job_t* job;
   char state[16];

   if(pool == NULL){
      _DOL_FPRINTF_(stderr,"thread_pool_runtime(NULL)/n");
      return;
   }

   pthread_mutex_lock(&(pool->pool_lock));
   fprintf(stdout,"/n *** thread pool runtime ***");
   fprintf(stdout,"/n size:%d/t job:%d/t reg_err:%d/n active:%d/t busy:%d/t idle:%d/t/n"
          ,pool->size,pool->total_job,pool->reg_err,pool->active,pool->busy,pool->idle);
   pthread_mutex_unlock(&(pool->pool_lock));

   fprintf(stdout,"/n id/t tid/t job/t stat/t desc/n");

   for(i=0; i<pool->size; i++){
      pthread_mutex_lock(&(pool->token[i].lock));
      if(pool->token[i].state != TREAD_POOL_STATE_NOTRUN){
         fprintf(stdout, " %d/t %u/t %d/t ",
            pool->token[i].token_id,pool->token[i].thread_id,pool->token[i].total_job);
         if(pool->token[i].state == TREAD_POOL_STATE_NOTRUN){
            sprintf(state,"NOTRUN");
         }else if(pool->token[i].state == TREAD_POOL_STATE_IDLE){
            sprintf(state,"IDLE");
         }else if(pool->token[i].state == TREAD_POOL_STATE_BUSY){
            sprintf(state,"BUSY");
         }else{
            sprintf(state,"UNKNW");
         }
         if(pool->token[i].job){
            fprintf(stdout, "%s/t %s/n",state,(pool->token[i].job)->desc);
         }else{
            fprintf(stdout, "%s/t N/A/n",state);
         }
      }
      pthread_mutex_unlock(&(pool->token[i].lock));
   }

#ifdef _THREAD_POOL_JOB_LIST_
   pthread_mutex_lock(&(pool->job_lock));
   job = pool->job_head;
   while(job){
      fprintf(stdout," N/A/t N/A/t N/A/t STDBY/t %s/n",job->desc);
      job = job->next;
   }
   pthread_mutex_unlock(&(pool->job_lock));
#endif
}

static int thread_pool_find_free_token(thread_pool_t * pool){
   int idx = -1, i;
   if(pool == NULL)
      return -1;

   for(i=0; i < pool->size; i++ ){
      pthread_mutex_lock(&(pool->token[i].lock));
      if(pool->token[i].state == TREAD_POOL_STATE_NOTRUN){
         idx = i;
      }
      pthread_mutex_unlock(&(pool->token[i].lock));
      if(idx != -1)
         break;
   }

   return idx;
}

static int thread_pool_find_serve_token(thread_pool_t * pool){
   int idx = -1, i = 0;
   if(pool == NULL)
      return -1;

   for(i=0; i<pool->size; i++ ){
      pthread_mutex_lock(&(pool->token[i].lock));
      if(pool->token[i].state == TREAD_POOL_STATE_IDLE){
         idx = i;
      }
      pthread_mutex_unlock(&(pool->token[i].lock));
      if(idx != -1)
         break;
   }

   return idx;
}

#ifdef _THREAD_POOL_JOB_LIST_
static thread_pool_job_t* pop_job(thread_pool_t * pool){
   thread_pool_job_t* job_node = NULL;
   if(pool){
      pthread_mutex_lock(&(pool->job_lock));
      job_node = pool->job_head;
      if(job_node && job_node->next){
         pool->job_head = job_node->next;
         job_node->next = NULL;
      }else{
         pool->job_head = NULL;
      }
      pthread_mutex_unlock(&(pool->job_lock));
   }
   return job_node;
}

static void push_job(thread_pool_t * pool, thread_pool_job_t* job){
   if(job == NULL)
      return;
   if(pool){
      pthread_mutex_lock(&(pool->job_lock));
      job->next = pool->job_head;
      pool->job_head = job;
      pthread_mutex_unlock(&(pool->job_lock));
   }
   return;
}

static void destroy_job_list(thread_pool_job_t* job_head){
   thread_pool_job_t* job_node ;
   while(job_head){
      job_node = job_head;
      job_head = job_head->next;
      free(job_node);
   }
   job_head = NULL;
   return;
}
#endif

 

3. thread_pool.def

 


#ifndef _THREAD_POOL_DEF_
#define _THREAD_POOL_DEF_

#ifndef _THREAD_POOL_JOB_LIST_
#define _THREAD_POOL_JOB_LIST_
#endif

//#ifndef _DEBUG_VERSION_
//#define _DEBUG_VERSION_
//#endif

#endif //end define _THREAD_POOL_DEF_

 

 

4.Makefile

 

obj=thread_pool.o
src=thread_pool.c
inc=thread_pool.h
def=thread_pool.def

target=$(obj)

.PHONY: all
.PHONY: clean
.PHONY: lib

all: $(target)
 @echo "Building Dolphin's Libaray"

$(obj): $(src) $(inc) $(def)
 gcc -g -c -fPIC $< -o $@

clean:
 rm -f *.o *.so *.a

lib: $(target)
 gcc -shared -fPIC -o libdol.so $(target)
 ar cr libdol.a $(target)

 

 

 

以上便是主要的源代码。

下面给出一个使用该线程池的例子: 


#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<signal.h>

#include "thread_pool.h"

int quit =0;

void sig_handler(int sig_no){
   quit = 1;
}

void call_back_func(void * arg ){
   int p = (int)(void*)arg;
   int i=0;
   while(!quit){
      //fprintf(stdout,"%-3d alive/n",p);
      sleep(1);
      break;
   }
}

int main(int argc, char** argv){
   thread_pool_t pool;
   job_call_back_t call_back;
   int i,rc;
   char desc [64];

   signal(SIGTERM, sig_handler);
   signal(SIGINT, sig_handler);

   rc = thread_pool_init(&pool, 5);
   thread_pool_set_log("./test_tp.log");
   if(rc != ETPOK){
      fprintf(stderr,"thread_pool_init fail/n");
      return 1;
   }

   sleep(2);
   call_back = call_back_func;

   for(i=0;i<10;i++){
      sprintf(desc,"job %d",i);
      //sleep(1);
      rc = thread_pool_register_job(&pool, call_back, (void*)i, desc);
      if(rc != TREAD_POOL_REG_OK){
         fprintf(stderr,"regiser %d %s fail/n",i,desc);
      }
   }

   while(!quit){
      thread_pool_runtime(&pool);
      sleep(1);
   }

   thread_pool_destroy(&pool);

   fprintf(stdout,"program stoping!/n");
   return 0;
}


Makefile:

 

exe=test_tp
src=test_tp.c
obj=test_tp.o

.PHONY: all
.PHONY: clean

all: $(exe)
clean:
 rm -f $(exe) $(obj)

$(exe): $(obj)
 gcc -g $^ -o $@ -lpthread -L.. -ldol
$(obj): $(src)
 gcc -g -c $< -o $@ -I..


 

你可能感兴趣的:(Linux C 实现线程池)