这里阅读了一份用C实现的线程池的设计,对其做了些注释,留作以后查看
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <pthread.h>
#include <assert.h>
/*任务结构体,构建成一个任务队列*/
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;//指向每个线程的id
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(sizeof(pthread_t) * max_thread_num);
int i = 0;
/*创建max_thread_num个线程*/
for(i=0; i < max_thread_num; i++)
{
pthread_create(&(pool->threadid[i]), NULL, thread_routine, NULL);
}
}
/*向线程池中的任务队列添加任务*/
int pool_add_worker(void *(*process)(void *), 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;//设置标志位,在thread_routine函数里会检测此标志位
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));
/*任务队列中没有任务可执行,就阻塞该线程,直到被唤醒*/
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)//线程池要销毁则终止该线程
{
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(pool->cur_queue_size != 0);
assert(pool->queue_head != NULL);
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;
}
pthread_exit(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(void)
{
int i = 0;
/*初始化线程池,这里创建了3个线程*/
pool_init(3);
/*创建10个任务,并加入到线程池的队列中去*/
int *workingnum = (int *)malloc(sizeof(int) * 10);
for(i=0; i < 10; i++)
{
workingnum[i] = i;
pool_add_worker(myprocess, &workingnum[i]);
}
/*等待所有的任务都完成*/
sleep(5);
/*销毁线程池*/
pool_destroy();
free(workingnum);
return 0;
}