线程池的简单实现
几个基本的线程函数:(本人有强迫症,为了分清返回值、函数名、参数列表,间距有点大,用的时候不要这样)
线程操纵函数
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 }