线程池

多线程技术主要解决处理器单元内多个线程执行的问题,它可以显著减少处理器单元的闲置时间,增加处理器单元的吞吐能力。但如果对多线程应用不当,会增加对单个任务的处理时间。可以举一个简单的例子:

假设在一台服务器完成一项任务的时间为T
T1 创建线程的时间
T2 在线程中执行任务的时间,包括线程间同步所需时间
T3 线程销毁的时间
显然T = T1+T2+T3。注意这是一个极度简化的假设。
可以看出T1,T3是多线程本身的带来的开销,我们渴望减少T1,T3所用的时间,从而减少T的时间。但一些线程的使用者并没有注意到这一点,所以在程序中频繁的创建或销毁线程,这导致T1和T3在T中占有相当比例。显然这是突出了线程的弱点(T1,T3),而不是优点(并发性)。
线程池技术正是关注如何缩短或调整T1,T3时间的技术,从而提高服务器程序性能的。它把T1,T3分别安排在服务器程序的启动和结束的时间段或者一些空闲的时间段,这样在服务器程序处理客户请求时,不会有T1,T3的开销了。
线程池不仅调整T1,T3产生的时间段,而且它还显著减少了创建线程的数目。


线程池至少包含下列组成部分:

1)线程池管理器:用于创建并管理线程池;

2)工作线程:线程池中的线程;

3)任务接口:每个任务必须实现的接口,以供工作线程调度任务的执行;

4)任务队列:存放没有处理的任务,提供一种缓冲机制。

什么时候需要创建线程池呢?简单的说,如果一个应用需要频繁的创建和销毁线程,而任务执行的时间又非常短,这样线程创建和销毁的带来的开销就不容忽视,这时也是线程池该出场的机会了。如果线程创建和销毁时间相比任务执行时间可以忽略不计,则没有必要使用线程池了。

  
下面是Linux系统下用C语言创建的一个线程池。线程池会维护一个任务链表(每个CThread_worker结构就是一个任务)。

   pool_init()函数预先创建好max_thread_num个线程。每个线程执thread_routine ()函数,该函数中

  1. while (pool->cur_queue_size == 0)
  2. {
  3.        pthread_cond_wait (&(pool->queue_ready),&(pool->queue_lock));
  4. }

表示如果任务链表中没有任务,则该线程出于阻塞等待状态。否则从队列中取出任务并执行。
   
   pool_add_worker()函数向线程池的任务链表中加入一个任务,加入后通过调用pthread_cond_signal (&(pool->queue_ready))唤醒一个出于阻塞状态的线程(如果有的话)。
   
   pool_destroy ()函数用于销毁线程池,线程池任务链表中的任务不会再被执行,但是正在运行的线程会一直把任务运行完后再退出。


下面贴出完整代码

#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;

} CThread_worker;


/*线程池结构*/
typedef struct
{
     pthread_mutex_t queue_lock;
     pthread_cond_t queue_ready;

    /*链表结构,线程池中所有等待任务*/
     CThread_worker *queue_head;

    /*是否销毁线程池*/
    int shutdown;
     pthread_t *threadid;
    /*线程池中允许的活动线程数目*/
    int max_thread_num;
    /*当前等待队列的任务数目*/
    int cur_queue_size;

} CThread_pool;


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


static CThread_pool *pool = NULL;
void
pool_init (int max_thread_num)
{
     pool = (CThread_pool *) malloc (sizeof (CThread_pool));

     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
pool_add_worker (void *(*process) (void *arg), void *arg)
{
    /*构造一个新任务*/
     CThread_worker *newworker =
         (CThread_worker *) malloc (sizeof (CThread_worker));
     newworker->process = process;
     newworker->arg = arg;
     newworker->next = NULL;/*别忘置空*/

     pthread_mutex_lock (&(pool->queue_lock));
    /*将任务加入到等待队列中*/
     CThread_worker *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);

    /*销毁等待队列*/
     CThread_worker *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;
}


void *
thread_routine (void *arg)
{
     printf ("starting thread 0x%x\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 0x%x 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 0x%x will exit\n", pthread_self ());
             pthread_exit (NULL);
         }

         printf ("thread 0x%x is starting to work\n", pthread_self ());

        /*assert是调试的好帮手*/
         assert (pool->cur_queue_size != 0);
         assert (pool->queue_head != NULL);
        
        /*等待队列长度减去1,并取出链表中的头元素*/
         pool->cur_queue_size--;
         CThread_worker *worker = pool->queue_head;
         pool->queue_head = worker->next;
         pthread_mutex_unlock (&(pool->queue_lock));

        /*调用回调函数,执行任务*/
         (*(worker->process)) (worker->arg);
         free (worker);
         worker = NULL;
     }
}

下面是测试代码

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

int
main (int argc, char **argv)
{
     pool_init (3);/*线程池中最多三个活动线程*/
    
    /*连续向池中投入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 (5);
    /*销毁线程池*/
     pool_destroy ();

     free (workingnum);
    return 0;
}

将上述所有代码放入threadpool.c文件中,
在Linux输入编译命令
$ gcc -lpthread threadpool.c   -o threadpool 

以下是运行结果
starting thread 0xb7df6b90
thread 0xb7df6b90 is waiting
starting thread 0xb75f5b90
thread 0xb75f5b90 is waiting
starting thread 0xb6df4b90
thread 0xb6df4b90 is waiting
thread 0xb7df6b90 is starting to work
threadid is 0xb7df6b90, working on task 0
thread 0xb75f5b90 is starting to work
threadid is 0xb75f5b90, working on task 1
thread 0xb6df4b90 is starting to work
threadid is 0xb6df4b90, working on task 2
thread 0xb7df6b90 is starting to work
threadid is 0xb7df6b90, working on task 3
thread 0xb75f5b90 is starting to work
threadid is 0xb75f5b90, working on task 4
thread 0xb6df4b90 is starting to work
threadid is 0xb6df4b90, working on task 5
thread 0xb7df6b90 is starting to work
threadid is 0xb7df6b90, working on task 6
thread 0xb75f5b90 is starting to work
threadid is 0xb75f5b90, working on task 7
thread 0xb6df4b90 is starting to work
threadid is 0xb6df4b90, working on task 8
thread 0xb7df6b90 is starting to work
threadid is 0xb7df6b90, working on task 9
thread 0xb75f5b90 is waiting
thread 0xb6df4b90 is waiting
thread 0xb7df6b90 is waiting
thread 0xb75f5b90 will exit
thread 0xb6df4b90 will exit

thread 0xb7df6b90 will exit


(代码摘自百度空间:http://hi.baidu.com/boahegcrmdghots/item/f3ca1a3c2d47fcc52e8ec2e1)




附上我自己写的代码:

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

typedef struct worker{
    int arg;
    struct worker *next;
}CThread_worker;

typedef struct {
    pthread_mutex_t mutex;
    pthread_cond_t cond;

    CThread_worker *queue_head;

    int shutdown;
    pthread_t * threadid;
    int max_thread_num;
    int cur_queue_size;
}CThread_pool;

static CThread_pool *pool = NULL;

void dowork(int arg)
{
    printf("The %dth worker is working,the threaddi is Ox%x.\n",arg,pthread_self());
    sleep(1);
}

int pool_add_worker(int num)
{
    CThread_worker *newworker=(CThread_worker*)malloc(sizeof(CThread_worker));
    newworker->arg=num;
    newworker->next=NULL;
    
    pthread_mutex_lock(&pool->mutex);
    CThread_worker *member=pool->queue_head;
    if(member!=NULL)
    {
        while(member->next !=NULL)
                member=member->next;
        member->next=newworker;
    }else{
        pool->queue_head = newworker;
    }
    pool->cur_queue_size++;
    pthread_mutex_unlock(&pool->mutex);
    pthread_cond_signal(&pool->cond);
    return 0;
}

int pool_destroy()
{
    if(pool->shutdown) return -1;
    pool->shutdown = 1;
    pthread_cond_broadcast(&pool->cond);
    int i;
    for(i=0;i<pool->max_thread_num;i++)
            pthread_join(pool->threadid[i],NULL);
    free(pool->threadid);

    CThread_worker *head=NULL;
    while(pool->queue_head !=NULL)
    {
            head=pool->queue_head;
            pool->queue_head=head->next;
            free(head);
    }
    pthread_mutex_destroy(&pool->mutex);
    pthread_cond_destroy(&pool->cond);
    free(pool);
    pool=NULL;
    return 0;
}

void *thread_runtine(void *arg)
{
    printf("Thread 0x%x is creating and starting.(thread_runtine)\n",pthread_self());
    while(1)
    {
        pthread_mutex_lock(&pool->mutex);
        while(pool->cur_queue_size==0&&!pool->shutdown)
        {
            printf("thread 0x%x is waiting.\n",pthread_self());
            pthread_cond_wait(&pool->cond,&pool->mutex);
        }
        if(pool->shutdown)
        {
            pthread_mutex_unlock(&pool->mutex);
            printf("thread 0x%x will exit.\n",pthread_self());
            pthread_exit(NULL);
        }
        pool->cur_queue_size --;
        CThread_worker *worker=pool->queue_head;
        pool->queue_head=pool->queue_head->next;
        pthread_mutex_unlock(&pool->mutex);
        dowork(worker->arg);
        free(worker);
        worker=NULL;
    }
}

//static CThread_pool *pool=NULL;
void pool_init(int num)
{
    pool=(CThread_pool *)malloc(sizeof(CThread_pool));
    pthread_mutex_init(&(pool->mutex),NULL);
    pthread_cond_init(&(pool->cond),NULL);
    pool->max_thread_num = num;
    pool->queue_head=NULL;
    pool->cur_queue_size=0;
    pool->shutdown=0;
    pool->threadid = (pthread_t *)malloc(num*sizeof(pthread_t));
    int i;
    for(i=0;i<num;i++)
    {
        pthread_create(&(pool->threadid[i]),NULL,thread_runtine,NULL);
    }
}

int main(int argc,char **argv)
{
    pool_init(10);
    
    int i;
    for(i=0;i<100;i++)
    {
        
        pool_add_worker(i);
    }
    sleep(30);
    pool_destroy();
    
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值