一个线程池例子

//c语言线程池实现
#ifndef __THREADPOOL__
#define __THREADPOOL__

#ifdef __cplusplus
extern "C" {
#endif 

//#endif

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/types.h>
#include<pthread.h>
#include<assert.h>

/*
*线程池里所有运行和等待的任务都是一个CThread_Worker
*由于所有任务都在链表里,所以是一个链表结构
*/

typedef struct Worker
{
    /*回调函数,任务运行时会调用此函数*/
    void (*process)(void *arg);
    void *arg;/*回调函数的参数*/
    struct Worker *next;    
}CThreadWorker;

/*线程池结构*/
typedef struct Pool
{
    pthread_mutex_t queue_lock;//互斥量
    pthread_cond_t   queue_ready;//条件变量
    /*链表结构,线程池中所有等待任务*/
    CThreadWorker *queue_head;
    int shutdown;//是否销毁线程池0为不销毁,1为销毁;
    pthread_t *threadid;
    int max_thread_num;//线程池中允许的活动线程数目;
    int cur_queue_size;//当前等待队列的任务数目;
}CThreadPool;

int pool_add_worker(void (*process)(void *arg),void *ptr);

void *thread_routine(void *arg);

static CThreadPool *pool =NULL;//线程池


void pool_init(int max_thread_num)
{
    //采用动态方式初始化条件变量和互斥量
    pool = (CThreadPool*)malloc(sizeof(CThreadPool));
    pthread_mutex_init(&(pool->queue_lock),NULL);
    pthread_cond_init(&(pool->queue_ready),NULL);

    pool->queue_head =NULL;
    pool->max_thread_num=max_thread_num;
    pool->cur_queue_size=0;
    pool->shutdown=0;

    pool->threadid = (pthread_t*)malloc(max_thread_num*sizeof(pthread_t));
    int i = 0;
    for(i=0;i<max_thread_num;i++)
    {
        pthread_create(&(pool->threadid[i]),NULL,thread_routine,NULL);//创建线程;
    }
    
}
/*
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
                          void *(*start_routine) (void *), void *arg);
void *(*start_routine) (void *)回调函数,指向返回值为指针的函数
*/

/*向线程池中加入任务*/
int pool_add_worker(void (*process)(void *arg),void *ptr)
{
    //构造一个新任务
    CThreadWorker *newworker=(CThreadWorker*)malloc(sizeof(CThreadWorker));
    newworker->process = process;
    newworker->arg = ptr;
    newworker->next =NULL;

    pthread_mutex_lock (&(pool->queue_lock)); 
      /*将任务加入到等待队列中*/ 
      CThreadWorker *member = pool->queue_head; 
      if (member != NULL) 
      { 
           while (member->next != NULL) 
           {
                     member = member->next; 
           }
             member->next = newworker; 
      } 
      else 
      { 
             pool->queue_head = newworker; 
      } 


     assert (pool->queue_head != NULL); 


     pool->cur_queue_size++; 
     pthread_mutex_unlock (&(pool->queue_lock)); 
    /*好了,等待队列中有任务了,唤醒一个等待线程; 
     注意如果所有线程都在忙碌,这句没有任何作用*/ 
     pthread_cond_signal (&(pool->queue_ready)); 
    return 0; 
}

/*销毁线程池,等待队列中的任务不会再被执行,但是正在运行的线程会一直 
把任务运行完后再退出*/ 
int pool_destroy () 
{ 
    if (pool->shutdown) 
        return -1;/*防止两次调用*/ 
     pool->shutdown = 1; 


    /*唤醒所有等待线程,线程池要销毁了*/ 
     pthread_cond_broadcast (&(pool->queue_ready)); 


    /*阻塞等待线程退出,否则就成僵尸了*/ 
    int i; 
    for (i = 0; i < pool->max_thread_num; i++) 
         pthread_join (pool->threadid[i], NULL); 
     free (pool->threadid); 


    /*销毁等待队列*/ 
     CThreadWorker *head = NULL; 
    while (pool->queue_head != NULL) 
     { 
         head = pool->queue_head; 
         pool->queue_head = pool->queue_head->next; 
         free (head); 
     } 
    /*条件变量和互斥量也别忘了销毁*/ 
     pthread_mutex_destroy(&(pool->queue_lock)); 
     pthread_cond_destroy(&(pool->queue_ready)); 
     
     free (pool); 
    /*销毁后指针置空是个好习惯*/ 
     pool=NULL; 
    return 0; 
} 

/*
pthread_t pthread_self(void);
函数作用:获得线程自身的ID。pthread_t的类型为unsigned long int,
所以在打印的时候要使用%lu方式,否则将产生奇怪的结果
*/
void * thread_routine (void *arg) 
{ 
    printf ("starting thread ---------------------%llu\n", pthread_self ()); 
    while (1) 
     { 
         pthread_mutex_lock (&(pool->queue_lock)); 
        /*如果等待队列为0并且不销毁线程池,则处于阻塞状态; 注意 
     pthread_cond_wait是一个原子操作,等待前会解锁,唤醒后会加锁*/ 
        while (pool->cur_queue_size == 0 && !pool->shutdown) 
         { 
             printf ("thread <%llu> is waiting\n", pthread_self ()); 
             pthread_cond_wait (&(pool->queue_ready), &(pool->queue_lock)); 
         } 


        /*线程池要销毁了*/ 
        if (pool->shutdown) 
         { 
            /*遇到break,continue,return等跳转语句,千万不要忘记先解锁*/ 
             pthread_mutex_unlock (&(pool->queue_lock)); 
             printf ("thread <%llu> will exit\n", pthread_self ()); 
             pthread_exit (NULL); 
         } 


         printf ("thread <%llu> is starting to work\n", pthread_self ()); 


        /*assert是调试的好帮手*/ 
         assert (pool->cur_queue_size != 0); 
         assert (pool->queue_head != NULL); 
         
        /*等待队列长度减去1,并取出链表中的头元素*/ 
         pool->cur_queue_size--; 
         CThreadWorker *worker = pool->queue_head; 
         pool->queue_head = worker->next;         /*调用回调函数,执行任务*/ 

         pthread_mutex_unlock (&(pool->queue_lock)); 
        
       //这里为什么用这种表达方式;还有别的写法吗?
         (*(worker->process)) (worker->arg); 
         free (worker); 
         worker = NULL; 
     } 
    /*这一句应该是不可达的*/ 
     pthread_exit (NULL); 
}


void myprocess (void *arg) 
{ 
     printf ("threadid is <%llu>, working on task %llu\n", pthread_self (),*(int *) arg); 
     sleep (1);/*休息一秒,延长任务的执行时间*/ 
    // return NULL; 
} 

int main (int argc, char **argv) 
{ 
     pool_init (3);/*线程池中最多三个活动线程*/ 
   //  getchar();
    sleep(50);
    /*连续向池中投入10个任务*/ 
    int *workingnum = (int *) malloc (sizeof (int) * 10); 
    int i; 
    for (i = 0; i < 10; i++) 
     { 
         workingnum[i] = i; 
         pool_add_worker (myprocess, &workingnum[i]); 
     } 
    /*等待所有任务完成*/ 
     sleep (50); 
    /*销毁线程池*/ 
     pool_destroy (); 


     free (workingnum); 
    return 0; 
}




#ifdef __cplusplus
}
#endif

#endif

 

posted @ 2013-07-10 21:26  z折腾  阅读(332)  评论(0编辑  收藏  举报