线程池的简单实现

几个基本的线程函数:(本人有强迫症,为了分清返回值、函数名、参数列表,间距有点大,用的时候不要这样)

线程操纵函数 

1 int  pthread_create  (pthread_t *tidp, const pthread_attr_t *attr, (void*)(*start_rtn)(void *), void *arg); //创建
2 void pthread_exit    (void *retval);            //终止自身
3 int  pthread_cancel  (pthread_t tid);             //终止其他.发送终止信号后目标线程不一定终止,要调用join函数等待
4 int  pthread_join    (pthread_t tid, void **retval);   //阻塞并等待其他线程

属性

1 int  pthread_attr_init            (pthread_attr_t *attr);           //初始化属性
2 int  pthread_attr_setdetachstate  (pthread_attr_t *attr, int detachstate); //设置分离状态
3 int  pthread_attr_destroy         (pthread_attr_t *attr);           //销毁属性

 

同步函数
互斥锁

1 int pthread_mutex_init    (pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr);  //初始化锁
2 int pthread_mutex_destroy (pthread_mutex_t *mutex);  //销毁锁
3 int pthread_mutex_lock    (pthread_mutex_t *mutex);  //加锁
4 int pthread_mutex_trylock (pthread_mutex_t *mutex);  //尝试加锁,上面lock的非阻塞版本
5 int pthread_mutex_unlock  (pthread_mutex_t *mutex);  //解锁

条件变量

1 int pthread_cond_init    (pthread_cond_t *cv, const pthread_condattr_t *cattr);  //初始化
2 int pthread_cond_destroy (pthread_cond_t *cond);                                 //销毁  
3 int pthread_cond_wait    (pthread_cond_t *cond, pthread_mutex_t *mutex);         //等待条件
4 int pthread_cond_signal  (pthread_cond_t *cond);                                 //通知,唤醒第一个调用pthread_cond_wait()而进入睡眠的线程

工具函数

1 int       pthread_equal  (pthread_t t1, pthread_t t2); //比较线程ID
2 int       pthread_detach (pthread_t tid);              //分离线程
3 pthread_t pthread_self   (void);                       //自身ID

 

上述代码中,线程的cancel和join,以及最后的工具函数,这些函数的参数都为结构体变量,其他的函数参数都是结构体变量指针;品味一下,参数为指针的,因为都需要改变结构体的内容,而参数为普通变量的,则只需要读内容即可。

 

线程池的优点可以自行百度一下, 一个线程池包括4个部分:

1、线程池管理器:用于创建、管理、销毁线程池
2、工作线程:线程池中线程
3、任务接口:线程要调用的函数,任务的具体实现函数
4、任务队列:用于存放没有处理的任务。提供一种缓冲机制。
 

线程池代码: 

  1 #include <stdio.h>
  2 #include <stdlib.h>
  3 #include <pthread.h>    //linux环境中多线程的头文件,非C语言标准库,编译时最后要加 -lpthread 调用动态链接库
  4 
  5 //任务链表的结构
  6 typedef struct worker 
  7 {
  8     void  *(*process) (void *arg);   //工作函数
  9     void  *arg;                      //函数的参数
 10     struct worker *next;
 11 }CThread_worker;
 12 
 13 //线程池的管理结构
 14 typedef struct 
 15 {
 16     pthread_mutex_t queue_lock;     //互斥锁
 17     pthread_cond_t  queue_ready;    //条件变量/信号量
 18 
 19     CThread_worker *queue_head;     //指向工作链表的头结点,临界区
 20     int cur_queue_size;             //记录链表中工作的数量,临界区
 21 
 22     int max_thread_num;             //最大线程数
 23     pthread_t *threadid;            //线程ID
 24 
 25     int shutdown;                   //开关
 26 }CThread_pool;
 27 
 28 static CThread_pool *pool = NULL;   //一个线程池变量
 29 int pool_add_worker(void *(*process)(void *arg), void *arg);    //负责向工作链表中添加实际的工作
 30 void *thread_routine(void *arg);    //线程例程
 31 
 32 //线程池初始化
 33 void
 34 pool_init(int max_thread_num)
 35 {
 36     int i = 0;
 37 
 38     pool = (CThread_pool *) malloc (sizeof(CThread_pool));    //创建线程池
 39 
 40     pthread_mutex_init(&(pool->queue_lock),  NULL);     //互斥锁初始化,参数为锁的地址
 41     pthread_cond_init( &(pool->queue_ready), NULL);     //条件变量初始化,参数为变量地址
 42 
 43     pool->queue_head = NULL;
 44     pool->cur_queue_size = 0;
 45 
 46     pool->max_thread_num = max_thread_num;
 47     pool->threadid = (pthread_t *)malloc(max_thread_num * sizeof(pthread_t));
 48     for (i = 0; i < max_thread_num; i++) 
 49     {
 50         pthread_create(&(pool->threadid[i]), NULL, thread_routine, NULL);  //创建线程, 参数为线程ID变量地址、属性、例程、参数
 51     }
 52 
 53     pool->shutdown = 0;
 54 }
 55 
 56 //例程,调用具体的工作函数
 57 void *
 58 thread_routine(void *arg)
 59 {
 60     //线程开始
 61     while(1)
 62     {
 63         pthread_mutex_lock(&(pool->queue_lock));    //从工作链表中取工作,要先加互斥锁,参数为锁地址
 64 
 65         while(pool->cur_queue_size == 0 && !pool->shutdown) 
 66         {   //链表为空,线程等待
 67             pthread_cond_wait(&(pool->queue_ready), &(pool->queue_lock));   //等待资源,信号量用于通知。会释放第二个参数的锁,以供添加;函数返回时重新加锁。
 68         }
 69 
 70         if(pool->shutdown) 
 71         {
 72             pthread_mutex_unlock(&(pool->queue_lock));          //结束开关开启,释放锁并退出线程
 73             pthread_exit(NULL);     //参数为void *
 74         }
 75     
 76         //线程准备工作
 77         --pool->cur_queue_size;
 78         CThread_worker *worker = pool->queue_head;
 79         pool->queue_head = worker->next;
 80 
 81         pthread_mutex_unlock (&(pool->queue_lock));     //获取一个工作后释放锁
 82 
 83 
 84         (*(worker->process))(worker->arg);      //做工作
 85         free(worker);
 86         worker = NULL;
 87     }
 88 
 89     pthread_exit(NULL);
 90 }
 91 
 92 //销毁线程池
 93 int
 94 pool_destroy()
 95 {
 96     if(pool->shutdown)      //检测结束开关是否开启,若开启,则所有线程会自动退出
 97         return -1;
 98     pool->shutdown = 1;
 99 
100     pthread_cond_broadcast( &(pool->queue_ready) );     //广播,唤醒所有线程,准备退出
101 
102     int i;
103     for(i = 0; i < pool->max_thread_num; ++i)
104         pthread_join(pool->threadid[i], NULL);  //主线程等待所有线程退出,只有join第一个参数不是指针,第二个参数类型是void **,接收exit的返回值,需要强制转换
105     free(pool->threadid);
106 
107     CThread_worker *head = NULL;
108     while(pool->queue_head != NULL)            //释放未执行的工作链表剩余结点
109     {
110         head = pool->queue_head;
111         pool->queue_head = pool->queue_head->next;
112         free(head);
113     }
114 
115     pthread_mutex_destroy(&(pool->queue_lock));     //销毁锁和条件变量
116     pthread_cond_destroy(&(pool->queue_ready));
117 
118     free(pool);
119     pool=NULL;
120     return 0;
121 }
122 
123 void *
124 myprocess(void *arg)
125 {
126     printf("threadid is 0x%x, working on task %d\n", (int)pthread_self(), *(int*)arg);    //工作函数,添加实际的代码,用sleep来代替
127     sleep (1);
128     return NULL;
129 }
130 
131 //添加工作
132 int
133 pool_add_worker(void *(*process)(void *arg), void *arg)
134 {
135     CThread_worker *newworker = (CThread_worker *) malloc(sizeof(CThread_worker));
136     newworker->process = process;   //具体的工作函数
137     newworker->arg = arg;
138     newworker->next = NULL;
139 
140     pthread_mutex_lock( &(pool->queue_lock) );      //加锁
141 
142     CThread_worker *member = pool->queue_head;      //插入链表尾部
143     if( member != NULL ) 
144     {
145         while( member->next != NULL )
146             member = member->next;
147         member->next = newworker;
148     }
149     else 
150     {
151         pool->queue_head = newworker;
152     }
153     ++pool->cur_queue_size;
154 
155     pthread_mutex_unlock( &(pool->queue_lock) );   //解锁
156 
157     pthread_cond_signal( &(pool->queue_ready) );   //通知一个等待的线程
158     return 0;
159 }
160 
161 int
162 main(int argc, char **argv)
163 {
164     pool_init(3);   //主线程创建线程池,3个线程
165 
166     int *workingnum = (int *) malloc(sizeof(int) * 10);
167     int i;
168     for(i = 0; i < 10; ++i) 
169     {
170         workingnum[i] = i;
171         pool_add_worker(myprocess, &workingnum[i]);     //主线程负责添加工作,10个工作
172     }
173 
174     sleep (5);
175     pool_destroy();     //销毁线程池
176     free (workingnum);
177 
178     return 0;
179 }

 

 

posted @ 2014-08-17 17:45  阿杰的专栏  阅读(353)  评论(0编辑  收藏  举报