线程池

 

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

    下面是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 ()函数用于销毁线程池,线程池任务链表中的任务不会再被执行,但是正在运行的线程会一直把任务运行完后再退出。
   
    下面贴出完整代码

1.#include <stdio.h>
2.#include <stdlib.h>
3.#include <unistd.h>
4.#include <sys/types.h>
5.#include <pthread.h>
6.#include <assert.h>
7.

8./*
9.*线程池里所有运行和等待的任务都是一个CThread_worker
10.*由于所有任务都在链表里,所以是一个链表结构
11.*/
12.typedef struct worker
13.{
14.    /*回调函数,任务运行时会调用此函数,注意也可声明成其它形式*/
15.    void *(*process) (void *arg);
16.    void *arg;/*回调函数的参数*/
17.    struct worker *next;
18.

19.} CThread_worker;
20.

21.

22./*线程池结构*/
23.typedef struct
24.{
25.    pthread_mutex_t queue_lock;
26.    pthread_cond_t queue_ready;
27.

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

31.    /*是否销毁线程池*/
32.    int shutdown;
33.    pthread_t *threadid;
34.    /*线程池中允许的活动线程数目*/
35.    int max_thread_num;
36.    /*当前等待队列的任务数目*/
37.    int cur_queue_size;
38.

39.} CThread_pool;
40.

41.

42.int pool_add_worker (void *(*process) (void *arg), void *arg);
43.void *thread_routine (void *arg);
44.

45.

46.static CThread_pool *pool = NULL;
47.void
48.pool_init (int max_thread_num)
49.{
50.    pool = (CThread_pool *) malloc (sizeof (CThread_pool));
51.

52.    pthread_mutex_init (&(pool->queue_lock), NULL);
53.    pthread_cond_init (&(pool->queue_ready), NULL);
54.

55.    pool->queue_head = NULL;
56.

57.    pool->max_thread_num = max_thread_num;
58.    pool->cur_queue_size = 0;
59.

60.    pool->shutdown = 0;
61.

62.    pool->threadid =
63.        (pthread_t *) malloc (max_thread_num * sizeof (pthread_t));
64.    int i = 0;
65.    for (i = 0; i < max_thread_num; i++)
66.    { 
67.        pthread_create (&(pool->threadid[i]), NULL, thread_routine,
68.                NULL);
69.    }
70.}
71.

72.

73./*向线程池中加入任务*/
74.int
75.pool_add_worker (void *(*process) (void *arg), void *arg)
76.{
77.    /*构造一个新任务*/
78.    CThread_worker *newworker =
79.        (CThread_worker *) malloc (sizeof (CThread_worker));
80.    newworker->process = process;
81.    newworker->arg = arg;
82.    newworker->next = NULL;/*别忘置空*/
83.

84.    pthread_mutex_lock (&(pool->queue_lock));
85.    /*将任务加入到等待队列中*/
86.    CThread_worker *member = pool->queue_head;
87.    if (member != NULL)
88.    {
89.        while (member->next != NULL)
90.            member = member->next;
91.        member->next = newworker;
92.    }
93.    else
94.    {
95.        pool->queue_head = newworker;
96.    }
97.

98.    assert (pool->queue_head != NULL);
99.

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

108.

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

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

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

127.    /*销毁等待队列*/
128.    CThread_worker *head = NULL;
129.    while (pool->queue_head != NULL)
130.    {
131.        head = pool->queue_head;
132.        pool->queue_head = pool->queue_head->next;
133.        free (head);
134.    }
135.    /*条件变量和互斥量也别忘了销毁*/
136.    pthread_mutex_destroy(&(pool->queue_lock));
137.    pthread_cond_destroy(&(pool->queue_ready));
138.    
139.    free (pool);
140.    /*销毁后指针置空是个好习惯*/
141.    pool=NULL;
142.    return 0;
143.}
144.

145.

146.void *
147.thread_routine (void *arg)
148.{
149.    printf ("starting thread 0x%x\n", pthread_self ());
150.    while (1)
151.    {
152.        pthread_mutex_lock (&(pool->queue_lock));
153.        /*如果等待队列为0并且不销毁线程池,则处于阻塞状态; 注意
154.        pthread_cond_wait是一个原子操作,等待前会解锁,唤醒后会加锁*/
155.        while (pool->cur_queue_size == 0 && !pool->shutdown)
156.        {
157.            printf ("thread 0x%x is waiting\n", pthread_self ());
158.            pthread_cond_wait (&(pool->queue_ready), &(pool->queue_lock));
159.        }
160.161.        /*线程池要销毁了*/
162.        if (pool->shutdown)
163.        {
164.            /*遇到break,continue,return等跳转语句,千万不要忘记先解锁*/
165.            pthread_mutex_unlock (&(pool->queue_lock));
166.            printf ("thread 0x%x will exit\n", pthread_self ());
167.            pthread_exit (NULL);
168.        }
169.170.        printf ("thread 0x%x is starting to work\n", pthread_self ());
171.172.        /*assert是调试的好帮手*/
173.        assert (pool->cur_queue_size != 0);
174.        assert (pool->queue_head != NULL);
175.        
176.        /*等待队列长度减去1,并取出链表中的头元素*/
177.        pool->cur_queue_size--;
178.        CThread_worker *worker = pool->queue_head;
179.        pool->queue_head = worker->next;
180.        pthread_mutex_unlock (&(pool->queue_lock));
181.182.        /*调用回调函数,执行任务*/
183.        (*(worker->process)) (worker->arg);
184.        free (worker);
185.        worker = NULL;
186.    }
187.    /*这一句应该是不可达的*/
188.    pthread_exit (NULL);
189.}
190.    下面是测试代码

1.void *
2.myprocess (void *arg)
3.{
4.    printf ("threadid is 0x%x, working on task %d\n", pthread_self (),*(int *) arg);
5.    sleep (1);/*休息一秒,延长任务的执行时间*/
6.    return NULL;
7.}
8.9.int
10.main (int argc, char **argv)
11.{
12.    pool_init (3);/*线程池中最多三个活动线程*/
13.    
14.    /*连续向池中投入10个任务*/
15.    int *workingnum = (int *) malloc (sizeof (int) * 10);
16.    int i;
17.    for (i = 0; i < 10; i++)
18.    {
19.        workingnum[i] = i;
20.        pool_add_worker (myprocess, &workingnum[i]);
21.    }
22.    /*等待所有任务完成*/
23.    sleep (5);
24.    /*销毁线程池*/
25.    pool_destroy ();
26.27.    free (workingnum);
28.    return 0;
29.}

本篇文章来源于 Linux公社网站(www.linuxidc.com)  原文链接:http://www.linuxidc.com/Linux/2011-04/34801.htm

 

 

 

 

 

 

 

 

/*
 小规模的Linux线程池
 written by luoxiongwei
 E-mail:luo6620378li@qq.com
 Welcom to report bugs!
 下一步计划给工作队列中的任务添加优先级
 实现一个优先队列。
*/

#ifndef __THREADPOOLS
#define __THREADPOOLS
#include <sys/types.h>
#include <pthread.h>
#include <unistd.h>
#include <vector>
#include <cstdio>
#include <cstdlib>
#include <cstring>

using std::vector;

struct task//队列中的任务结点
{
   void (*handler)(void *);//任务函数
   void * data;//任务数据
   //int prority;//任务优先级
};

struct  work_queue_t//工作队列
{
  struct work_queue_t * next ;
  struct work_queue_t * head ;
  struct work_queue_t * tail ;
  struct task * elment ;
};

//工作队列操作
work_queue_t * init_work_queue();//初始化工作队列
void destory_work_queue();//销毁工作队列
work_queue_t * remove_task();//取队首任务
int add_tast(task * new_task);//在工作队列尾部添加任务
bool empty();


//线程池资源
void *thread_rounter(void *);//线程执行函数
struct work_queue_t *  work_queue=NULL;//工作队列
int work_count=0;//工作队列中的元素个数
vector<pthread_t> threads;//记录所有线程的id
pthread_cond_t pool_cond;//唤醒相应线程开始工作
pthread_mutex_t queue_lock;//保护工作队列,以及池中的互斥资源
int idles;//空闲线程数目
int busy;//正在执行任务的线程数目
int max_thread;//池中维持的最大线程数目
bool to_exit;//销毁线程池标志
bool validate;//线程池是否可用

//线程池操作,提供给用户操作的四个函数
void thread_pool(int init_threads_num);//建立线程池
void destroy_thread_pool();//销毁线程池

/*组装任务处理函数和处理函数参数,注意一旦该任务完成之后,
  数据将会被系统释放掉,所以下一次向线程池加入任务时,
  请重新组装。请保证处理函数是线程可重入的。
*/
task * prod_task(void (*handler)(void *), void * data);
int exec_task(task * new_task);//留给用户的调用接口

#endif

//示例的工作函数
void task1(void *arg);

int main()
{
    //现在测试了池中有10个线程,12个任务。

    //任务参数
  char *ptr1="I am task one\n";
  char *ptr2="I am task two\n";
  char *ptr3="I am task three\n";
  char *ptr4="I am task four\n";
  char *ptr5="I am task five\n";
  char *ptr6="I am task six\n";
  char *ptr7="I am task seven\n";
  char *ptr8="I am task eight\n";
  char *ptr9="I am task nine\n";
  char *ptr10="I am task ten\n";
  char *ptr11="I am task eleven\n";
  char *ptr12="I am task twltle\n";

  //组装任务
  task * task_p1=prod_task(task1,ptr1);
  task * task_p2=prod_task(task1,ptr2);
  task * task_p3=prod_task(task1,ptr3);
  task * task_p4=prod_task(task1,ptr4);
  task * task_p5=prod_task(task1,ptr5);
  task * task_p6=prod_task(task1,ptr6);
  task * task_p7=prod_task(task1,ptr7);
  task * task_p8=prod_task(task1,ptr8);
  task * task_p9=prod_task(task1,ptr9);
  task * task_p10=prod_task(task1,ptr10);
  task * task_p11=prod_task(task1,ptr11);
  task * task_p12=prod_task(task1,ptr12);

  thread_pool(10);//建立线程池,池中最多10个线程

  //12个任务
  exec_task(task_p1);
  exec_task(task_p2);
  exec_task(task_p3);
  exec_task(task_p4);
  exec_task(task_p5);
  exec_task(task_p6);
  exec_task(task_p7);
  exec_task(task_p8);
  exec_task(task_p9);
  exec_task(task_p10);
  exec_task(task_p11);
  exec_task(task_p12);

  /*延时,让所有任务执行完。也可以不延时,
    但是可能任务还没有完成,线程池就被销毁。
  */
  sleep(20);

 destroy_thread_pool();//销毁线程池

  return 0;
}


void task1(void *arg)
{
    char *ptr=(char *)arg;
    write(STDOUT_FILENO,ptr,strlen(ptr));
}

//提供给用户的外部接口之一,生成任务
task * prod_task(void (*handler)(void *), void * data)
{
  struct task * new_task=new task;
   if(!new_task)
     return NULL;

  new_task->handler=handler;
  new_task->data=data;
  return new_task;
}


//工作队列的相应操作
work_queue_t * init_work_queue()
{
      work_queue_t *work_queue_=new work_queue_t ;
       if(!work_queue_)
         return NULL;

      work_queue_->head=work_queue_->tail=NULL;
      work_queue_->next=NULL;
      work_queue_->elment=NULL;
      work_count=0;
      return work_queue_;
}


work_queue_t * remove_task()//取队首任务
{
 work_queue_t * temp;
  if(empty())//工作队列空
   return NULL;

    temp=work_queue->head;
    work_queue->head=work_queue->head->next;
    work_count--;
 return temp;
}

//在工作队列尾部添加任务
int add_tast(task * new_task)
{
 work_queue_t * temp=NULL;

  if(empty())//队列为空
  {
     temp=new   work_queue_t ;
     temp->next=NULL;
     temp->elment=new_task;
    work_queue->head=work_queue->tail=temp;
    work_count++;
     return 0;
  }
  else//队列不空
  {
        temp=new   work_queue_t  ;
        temp->next=NULL;
        temp->elment=new_task;
       work_queue->tail->next=temp;
       work_queue->tail=temp;
       work_count++;
       return 0;
  }
   return -1;//添加不成功

}

void destory_work_queue()
{
  work_queue_t * temp;
  if(work_count!=0)
      {
          while(work_queue->head)
       {
         temp=work_queue->head;
         work_queue->head=work_queue->head->next;
         delete temp->elment;
         delete temp;
       }
      }
}
bool empty()
{
bool flage=false;

  if(work_count==0)
   flage=true;

 return flage;
}

//线程池的操作

//初始化线程池
void thread_pool(int init_threads_num)
{
   pthread_mutex_init(&queue_lock,NULL);//初始化锁

 if(pthread_cond_init(&pool_cond,NULL)!=0)
     return ;
  work_queue=init_work_queue();//工作队列

  if(!work_queue)
   return ;
  max_thread=init_threads_num;
  idles=0;
  busy=0;
  to_exit=false;
  validate=true;

}

//销毁线程池和工作队列,条件变量,锁
void destroy_thread_pool()
{
  pthread_mutex_lock(&queue_lock);
  //改变条件
   to_exit=true;
   validate=false;

    //取消线程池中的所有线程
    for(size_t i=0;i!=threads.size();++i)
        pthread_cancel(threads[i]);

     //销毁工作队列
    destory_work_queue();
   pthread_mutex_unlock(&queue_lock);

    //销毁锁和条件变量
   pthread_mutex_destroy(&queue_lock);
   pthread_cond_destroy(&pool_cond);

}

int exec_task(task * new_task)
{
  pthread_t tid;

    pthread_mutex_lock(&queue_lock);
     //将新任务添加至工作队列
   if(add_tast(new_task)!=0)
     {
       pthread_mutex_unlock(&queue_lock);
       return -1;
     }


    pthread_cond_signal(&pool_cond);//工作队列中有任务了,唤醒一个阻塞线程

   //是否新建线程,视条件而定
   if(validate&&!to_exit&&(idles==0||(idles+busy)<max_thread))
    {
      if(pthread_create(&tid,NULL,thread_rounter,NULL)!=0)
        {
          pthread_mutex_unlock(&queue_lock);
          return -1;
        }
       threads.push_back(tid);//记录线程id
      idles++;//多了一个空闲线程
       pthread_mutex_unlock(&queue_lock);
      return 0;
    }
   pthread_mutex_unlock(&queue_lock);
   return 0;
}

void *thread_rounter(void *)
{
  pthread_detach(pthread_self());//分离自己
  pthread_setcancelstate(PTHREAD_CANCEL_ENABLE,NULL);
  pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED,NULL);//到达取消点处才取消线程

  work_queue_t * work_item=NULL;

  for(;;)//去检查工作队列中是否有需要处理的工作项目
    {
       pthread_mutex_lock(&queue_lock);
       while(validate&&!to_exit&&((work_item=remove_task())==NULL))//工作队列为空,则一直等待
        pthread_cond_wait(&pool_cond,&queue_lock);//这里将会是一个取消点

       pthread_mutex_unlock(&queue_lock);

      if(validate&&!to_exit&&work_item->elment->data)
        {
           pthread_mutex_lock(&queue_lock);
             busy++;//该线程忙
             idles--;
           pthread_mutex_unlock(&queue_lock);

          work_item->elment->handler(work_item->elment->data);//处理函数调用

           pthread_mutex_lock(&queue_lock);
             busy--;
             idles++;
           pthread_mutex_unlock(&queue_lock);

             //释放资源
              delete work_item->elment;
              delete work_item;
        }
    }
    return NULL;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值